prepper 0.1.0 → 0.2.1

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: d68d0ee338e47bb82505f4b37da819ea323e77de3f3e49cba9bbec6d4d5f6d04
4
- data.tar.gz: 32e04ba18f7dbaf9397ee08a3dfb6a72e18026fb54b157c3b3649ce1ab792f54
3
+ metadata.gz: 77a7a8da09385a93046fcd636b90eaddd34fe8bc4ed9c3a9a103e0f5e383402a
4
+ data.tar.gz: 4f0ff1b545ba8c603f362ede36ab62bd63f8352c26de97830d2cabf8fabbd3c0
5
5
  SHA512:
6
- metadata.gz: f71e24560ab3572628fdc97e663da08142af71ef848ac096dc988d37b0bf2c3c7abe712520b4a2a418d7d29d5676b3ff6a27577a8cc559b5fd3151c6ca220ec2
7
- data.tar.gz: ecef0450a23ff26eef8ea203638c3b9ca22f19cbd9648795246d7cdb242e9be0fcf4378fb91a0e68535ede0c9b2e2117509e7e84c4711defbc7c127fb728709a
6
+ metadata.gz: d251c3448c12d5accc5ee510b42df6180fcbaa30f2757ec1abdfd36ac25c8875a93f06f07fff6e80350a0809185dea9cba088e5f107c6b090e01088aa2ce8ffe
7
+ data.tar.gz: 28fd214634b0a79c171c5d9712686e84ebe10084f7e5a9f854918fd4bb0bc998dbcd2b010185d0b738833fc20d18a4dcc60ea1f5e4d595af526a77684b114160
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_dispatch:
7
+ # schedule:
8
+ # - cron: '42 5 * * *'
9
+
10
+ jobs:
11
+ test:
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ ruby: [ '3.0' ]
16
+
17
+ runs-on: ubuntu-latest
18
+ name: Ruby ${{matrix.ruby}}
19
+ container: ruby:${{matrix.ruby}}
20
+
21
+ steps:
22
+ - uses: actions/checkout@v3
23
+
24
+ - name: Show ruby Version
25
+ run: |
26
+ ruby -v
27
+
28
+ - name: Install Modules
29
+ run: ./bin/setup
30
+
31
+ - name: Run tests
32
+ run: rake test
33
+
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Change log
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.2.0
6
+
7
+ * better docs
8
+
9
+ ## 0.1.0
10
+
11
+ * First release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prepper (0.1.0)
4
+ prepper (0.2.1)
5
5
  sshkit
6
6
  tty-option
7
7
  zeitwerk
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Prepper
2
2
 
3
3
  Prepper is a simple server provisioning tool, built on top of SSHKit. You can
4
- use it to script your server build process.
4
+ use it to script your server build process. It is heavily inspired by (Sprinkle)[https://github.com/sprinkle-tool/sprinkle], but Sprinkle doesn't seem to be maintained anymore, that's why Prepper was born.
5
5
 
6
6
 
7
7
  ## Installation
@@ -17,7 +17,8 @@ upload files to the server, etc.
17
17
 
18
18
  A simple example:
19
19
 
20
- ```
20
+ ```ruby
21
+
21
22
  server_host "YOUR_SERVER_IP"
22
23
  server_port 22
23
24
  server_user "root"
@@ -47,6 +48,8 @@ end
47
48
 
48
49
  You can see a full example in [examples/config.rb](examples/config.rb). You would run that file with `bundle exec prepper config.rb` to provision the server.
49
50
 
51
+ The API documentation can be found on rubydoc: [https://rubydoc.info/github/gregmolnar/prepper](https://rubydoc.info/github/gregmolnar/prepper).
52
+
50
53
  ## Development
51
54
 
52
55
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -55,7 +58,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
55
58
 
56
59
  ## Contributing
57
60
 
58
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/prepper. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/prepper/blob/master/CODE_OF_CONDUCT.md).
61
+ Bug reports and pull requests are welcome on GitHub at https://github.com/gregmolnar/prepper. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/gregmolnar/prepper/blob/master/CODE_OF_CONDUCT.md).
59
62
 
60
63
 
61
64
  ## License
@@ -64,4 +67,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
64
67
 
65
68
  ## Code of Conduct
66
69
 
67
- Everyone interacting in the Prepper project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/prepper/blob/master/CODE_OF_CONDUCT.md).
70
+ Everyone interacting in the Prepper project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/gregmolnar/prepper/blob/master/CODE_OF_CONDUCT.md).
@@ -1,27 +1,25 @@
1
1
  module Prepper
2
2
  module Tools
3
+ # Helper methods to interact with Apt
3
4
  module Apt
4
- def self.included(base)
5
- base.class_eval do
6
-
7
- # Updates apt repositories
8
- def apt_update
9
- @commands << Command.new("apt update", sudo: true)
10
- end
11
-
12
- # Installs packages
13
- # @param packages [Array] array of package names
14
- def apt_install(packages)
15
- packages.each do |package|
16
- @commands << Command.new("apt install --force-yes -qyu #{package}", sudo: true, verify: has_apt_package?(package))
17
- end
18
- end
5
+ # Updates apt repositories
6
+ def apt_update
7
+ @commands << Command.new("apt update", sudo: true)
8
+ end
19
9
 
20
- def has_apt_package?(package)
21
- Command.new("dpkg --status #{package} | grep 'ok installed'", sudo: true)
22
- end
10
+ # Installs packages
11
+ # @param packages [Array] array of package names
12
+ def apt_install(packages)
13
+ packages.each do |package|
14
+ @commands << Command.new("apt install --force-yes -qyu #{package}", sudo: true, verify: has_apt_package?(package))
23
15
  end
24
16
  end
17
+
18
+ # Verifier command to checks if an apt package is installed
19
+ # @param package [String] name of the package
20
+ def has_apt_package?(package)
21
+ Command.new("dpkg --status #{package} | grep 'ok installed'", sudo: true)
22
+ end
25
23
  end
26
24
  end
27
25
  end
@@ -2,67 +2,121 @@ require 'erb'
2
2
  require 'digest/md5'
3
3
  module Prepper
4
4
  module Tools
5
+ # Helper methods for file and directory management
5
6
  module File
6
- def self.included(base)
7
- base.class_eval do
8
7
 
9
- def chown(path, owner, flags = "")
10
- @commands << Command.new("chown #{flags} #{owner} #{path}", sudo: true)
11
- end
8
+ # Changes ownership of a path
9
+ # @param path [String] the path which we want to change the ownership of
10
+ # @param owner [String] name of the owner, ie: 'root:root'
11
+ # @param flags [String] flags to pass to chown, ie: '-R' to do it recursively
12
+ def chown(path, owner, flags = "")
13
+ @commands << Command.new("chown #{flags} #{owner} #{path}", sudo: true)
14
+ end
12
15
 
13
- def directory(path, opts = {})
14
- @commands << Command.new("mkdir -p #{path}", opts.merge(sudo: true, verifier: has_directory?(path)))
15
- @commands << Command.new("chown #{opts[:owner]} #{path}", sudo: true) if opts[:owner]
16
- @commands << Command.new("chmod #{opts[:mode]} #{path}", sudo: true) if opts[:mode]
17
- end
16
+ # Create a directory unless it already exists
17
+ # @param path [String] path of the directory
18
+ # @param [Hash] opts options hash
19
+ # @option opts [String] :owner Owner of the directory, ie: 'root:root'
20
+ # @option opts [String] :mode mode bits, ie: '0777'
21
+ def directory(path, opts = {})
22
+ @commands << Command.new("mkdir -p #{path}", opts.merge(sudo: true, verifier: has_directory?(path)))
23
+ @commands << Command.new("chown #{opts[:owner]} #{path}", sudo: true) if opts[:owner]
24
+ @commands << Command.new("chmod #{opts[:mode]} #{path}", sudo: true) if opts[:mode]
25
+ end
18
26
 
19
- def has_directory?(path)
20
- Command.new("test -d #{path}", sudo: true)
21
- end
27
+ # returns a verifier command to test if a directory exists
28
+ # @param path [String] path to test
29
+ def has_directory?(path)
30
+ Command.new("test -d #{path}", sudo: true)
31
+ end
22
32
 
23
- def file(path, opts = {})
24
- opts[:locals] ||= {}
25
- opts[:verify_content] ||= true
26
- content = opts[:content] || render_template(opts[:template], opts[:locals])
27
- verifier = if opts[:verify_content]
28
- matches_content?(path, content)
29
- else
30
- has_file?(path)
31
- end
32
- io = StringIO.new(content)
33
- @commands << Command.new("put!", {params: [io, path, {owner: opts[:owner], mode: opts[:mode]}], verifier: verifier})
34
- end
33
+ # Create a file unless it already exists. The contents can be set to a
34
+ # string or a template can be rendered with the provided locals
35
+ # @param path [String] path of the file
36
+ # @param [Hash] opts options hash
37
+ # @option opts [String] :content string content of the file
38
+ # @option opts [String] :template name of the template for the file
39
+ # @option opts [String] :locals hash of variables to pass to the template
40
+ # @option opts [String] :verify_content set to true to verify the file
41
+ # content is the same in case the file already exists
42
+ # @option opts [String] :owner Owner of the directory, ie: 'root:root'
43
+ # @option opts [String] :mode mode bits, ie: '0777'
44
+ def file(path, opts = {})
45
+ opts[:locals] ||= {}
46
+ opts[:verify_content] ||= true
47
+ content = opts[:content] || render_template(opts[:template], opts[:locals])
48
+ verifier = if opts[:verify_content]
49
+ matches_content?(path, content)
50
+ else
51
+ has_file?(path)
52
+ end
53
+ io = StringIO.new(content)
54
+ @commands << Command.new("put!", {params: [io, path, {owner: opts[:owner], mode: opts[:mode]}], verifier: verifier})
55
+ end
35
56
 
36
- def has_file?(path)
37
- Command.new("test -f #{path}", sudo: true)
38
- end
57
+ # returns a verifier command to test if a file exists
58
+ # @param path [String] path to test
59
+ def has_file?(path)
60
+ Command.new("test -f #{path}", sudo: true)
61
+ end
39
62
 
40
- def matches_content?(path, content)
41
- md5 = Digest::MD5.hexdigest(content)
42
- Command.new("md5sum #{path} | cut -f1 -d' '`\" = \"#{md5}\"", sudo: true, verifier: has_file?(path))
43
- end
63
+ # returns a verifier command to test if has a matching content
64
+ # @param path [String] path to test
65
+ # @param content [String] expected content
66
+ def matches_content?(path, content)
67
+ md5 = Digest::MD5.hexdigest(content)
68
+ Command.new("md5sum #{path} | cut -f1 -d' '`\" = \"#{md5}\"", sudo: true, verifier: has_file?(path))
69
+ end
44
70
 
45
- def symlink(link, target, opts = {})
46
- opts.merge!(
47
- sudo: true,
48
- verifier: has_symlink?(link)
49
- )
50
- @commands << Command.new("ln -s #{target} #{link}", opts)
51
- end
71
+ # creates a symlink
72
+ # @param link [String] link
73
+ # @param target [String] target
74
+ # @param [Hash] opts options hash
75
+ def symlink(link, target, opts = {})
76
+ opts.merge!(
77
+ sudo: true,
78
+ verifier: has_symlink?(link)
79
+ )
80
+ @commands << Command.new("ln -s #{target} #{link}", opts)
81
+ end
82
+
83
+ # returns a verifier command to test if as a matching content
84
+ # @param path [String] path to test
85
+ # @param content [String] expected content
86
+ def matches_content?(path, content)
87
+ md5 = Digest::MD5.hexdigest(content)
88
+ Command.new("md5sum #{path} | cut -f1 -d' '`\" = \"#{md5}\"", sudo: true, verifier: has_file?(path))
89
+ end
52
90
 
53
- def has_symlink?(link, file = nil)
54
- if file
55
- Command.new("'#{file}' = `readlink #{link}`")
56
- else
57
- Command.new("test -L #{link}", sudo: true)
58
- end
59
- end
91
+ # creates a symlink
92
+ # @param link [String] link
93
+ # @param target [String] target
94
+ # @param [Hash] opts options hash
95
+ def symlink(link, target, opts = {})
96
+ opts.merge!(
97
+ sudo: true,
98
+ verifier: has_symlink?(link)
99
+ )
100
+ @commands << Command.new("ln -s #{target} #{link}", opts)
101
+ end
60
102
 
61
- def render_template(template, locals)
62
- ERB.new(::File.read("./templates/#{template}")).result_with_hash(locals)
63
- end
103
+ # returns a verifier command to test if symlink exists
104
+ # @param path [String] path to test
105
+ # @param file [String] optionally check if it points to the correct file
106
+ def has_symlink?(link, file = nil)
107
+ if file
108
+ Command.new("'#{file}' = `readlink #{link}`")
109
+ else
110
+ Command.new("test -L #{link}", sudo: true)
64
111
  end
65
112
  end
113
+
114
+ # render an ERB template
115
+ # @param template [String] name of the template
116
+ # @param locals [Hash] hash of variables to pass to the template
117
+ def render_template(template, locals)
118
+ ERB.new(::File.read("./templates/#{template}")).result_with_hash(locals)
119
+ end
66
120
  end
67
121
  end
68
122
  end
@@ -1,27 +1,28 @@
1
1
  module Prepper
2
2
  module Tools
3
+ # Helper methods for rbenv
3
4
  module Rbenv
4
- def self.included(base)
5
- base.class_eval do
5
+ # install rbenv for a given user
6
+ # @param user [String] name of the user to install rbenv for
7
+ def install_rbenv(user)
8
+ apt_install %w{libssl-dev zlib1g zlib1g-dev libreadline-dev}
9
+ @commands << Command.new("sudo -u #{user} -i git clone https://github.com/sstephenson/rbenv.git /home/#{user}/.rbenv", verifier: has_directory?("/home/#{user}/.rbenv"))
10
+ @commands << Command.new("sudo -u #{user} -i git clone https://github.com/sstephenson/ruby-build.git /home/#{user}/.rbenv/plugins/ruby-build", verifier: has_directory?("/home/#{user}/.rbenv/plugins/ruby-build"))
6
11
 
7
- def install_rbenv(user)
8
- apt_install %w{libssl-dev zlib1g zlib1g-dev libreadline-dev}
9
- @commands << Command.new("sudo -u #{user} -i git clone https://github.com/sstephenson/rbenv.git /home/#{user}/.rbenv", verifier: has_directory?("/home/#{user}/.rbenv"))
10
- @commands << Command.new("sudo -u #{user} -i git clone https://github.com/sstephenson/ruby-build.git /home/#{user}/.rbenv/plugins/ruby-build", verifier: has_directory?("/home/#{user}/.rbenv/plugins/ruby-build"))
11
-
12
- append_text 'export PATH="$HOME/.rbenv/bin:$PATH"', "/home/#{user}/.profile"
13
- append_text 'eval "$(rbenv init -)"', "/home/#{user}/.profile"
14
- chown "/home/#{user}/.profile", 'deploy:deploy'
15
- end
12
+ append_text 'export PATH="$HOME/.rbenv/bin:$PATH"', "/home/#{user}/.profile"
13
+ append_text 'eval "$(rbenv init -)"', "/home/#{user}/.profile"
14
+ chown "/home/#{user}/.profile", "#{user}:#{user}"
15
+ end
16
16
 
17
- def install_ruby(user, version, opts = '')
18
- @commands << Command.new("sudo -u #{user} -i RUBY_CONFIGURE_OPTS='#{opts}' rbenv install #{version}", verifier: has_directory?("/home/#{user}/.rbenv/versions/#{version}"))
17
+ # install a given ruby version for a given user
18
+ # @param user [String] name of the user
19
+ # @param version [String] ruby version
20
+ def install_ruby(user, version, opts = '')
21
+ @commands << Command.new("sudo -u #{user} -i RUBY_CONFIGURE_OPTS='#{opts}' rbenv install #{version}", verifier: has_directory?("/home/#{user}/.rbenv/versions/#{version}"))
19
22
 
20
- @commands << Command.new("sudo -u #{user} -i rbenv rehash")
21
- @commands << Command.new("sudo -u #{user} -i rbenv global #{version}")
22
- @commands << Command.new("sudo -u #{user} -i rbenv rehash")
23
- end
24
- end
23
+ @commands << Command.new("sudo -u #{user} -i rbenv rehash")
24
+ @commands << Command.new("sudo -u #{user} -i rbenv global #{version}")
25
+ @commands << Command.new("sudo -u #{user} -i rbenv rehash")
25
26
  end
26
27
  end
27
28
  end
@@ -1,18 +1,20 @@
1
1
  module Prepper
2
2
  module Tools
3
+ # text related helpers
3
4
  module Text
4
- def self.included(base)
5
- base.class_eval do
6
-
7
- def append_text(text, path)
8
- @commands << Command.new("/bin/echo -e '#{text}' | sudo tee -a #{path}", verifier: has_text?(text, path))
9
- end
5
+ # append text to a file
6
+ # @param text [String] text to append
7
+ # @param path [String]
8
+ def append_text(text, path)
9
+ @commands << Command.new("/bin/echo -e '#{text}' | sudo tee -a #{path}", verifier: has_text?(text, path))
10
+ end
10
11
 
11
- def has_text?(text, path)
12
- regex = Regexp.escape(text)
13
- Command.new("grep -qPzo '^#{regex}$' #{path} ||", sudo: true)
14
- end
15
- end
12
+ # returns a verifier command to test the presence of a string in a file
13
+ # @param text [String] text
14
+ # @param path [String] path to file
15
+ def has_text?(text, path)
16
+ regex = Regexp.escape(text)
17
+ Command.new("grep -qPzo '^#{regex}$' #{path} ||", sudo: true)
16
18
  end
17
19
  end
18
20
  end
@@ -1,22 +1,27 @@
1
1
  module Prepper
2
2
  module Tools
3
+ # user management related helpers
3
4
  module Users
4
- def self.included(base)
5
- base.class_eval do
6
- def add_user(username, opts = {})
7
- opts[:flags] << ' --gecos ,,,'
8
- @commands << Command.new("adduser #{username} #{opts[:flags]}", sudo: true, verifier: has_user?(username))
9
- end
5
+ # add a user to the host
6
+ # @param username [String] name of the user
7
+ # @param [Hash] opts options has
8
+ # @option opts [String] :flags flags to pass to adduser
9
+ def add_user(username, opts = {})
10
+ opts[:flags] << ' --gecos ,,,'
11
+ @commands << Command.new("adduser #{username} #{opts[:flags]}", sudo: true, verifier: has_user?(username))
12
+ end
10
13
 
11
- def has_user?(username, opts = {})
12
- if opts[:in_group]
13
- command = "id -nG #{username} | xargs -n1 echo | grep #{opts[:in_group]}"
14
- else
15
- command = "id #{username}"
16
- end
17
- Command.new(command, sudo: true)
18
- end
14
+ # returns a verifier command to check if a user exists
15
+ # @param username [String] name of the user
16
+ # @param [Hash] opts options hash
17
+ # @option opts [String] :in_group check if the user is in the given group
18
+ def has_user?(username, opts = {})
19
+ if opts[:in_group]
20
+ command = "id -nG #{username} | xargs -n1 echo | grep #{opts[:in_group]}"
21
+ else
22
+ command = "id #{username}"
19
23
  end
24
+ Command.new(command, sudo: true)
20
25
  end
21
26
  end
22
27
  end
@@ -1,3 +1,3 @@
1
1
  module Prepper
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prepper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Molnar
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-16 00:00:00.000000000 Z
11
+ date: 2023-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -74,8 +74,10 @@ executables:
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
+ - ".github/workflows/ci.yml"
77
78
  - ".gitignore"
78
79
  - ".travis.yml"
80
+ - CHANGELOG.md
79
81
  - CODE_OF_CONDUCT.md
80
82
  - Gemfile
81
83
  - Gemfile.lock