herd-rb 0.2.0 → 0.3.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 +4 -4
- data/.ruby-version +1 -0
- data/README.md +21 -2
- data/TODO.md +20 -0
- data/lib/herd/host.rb +7 -4
- data/lib/herd/runner.rb +2 -2
- data/lib/herd/session/commands/authorized_keys.rb +18 -0
- data/lib/herd/session/commands/packages.rb +13 -0
- data/lib/herd/session.rb +62 -17
- data/lib/herd/version.rb +1 -1
- metadata +8 -59
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f0b080c1095b56bac42536acc7df54cd20c97bac52f2367301e2b951eb8a60be
|
|
4
|
+
data.tar.gz: 397b3c9636a2dc20310f8e70fbe3911049bde76183fe8650f30d0cff4bb40402
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 514947c517caa05fc2229c6d293042bf6065ad2d067574087d479772fac271802279f769a6f98d33ae0c7a09720bd99e6592b475e2e6cc3934c515d970323bc1
|
|
7
|
+
data.tar.gz: 7962d18779bc695f3858adcbf40dc75350e9d88ec00a29b0ab71b8e9ab8ffd21b18f28e8078c2e012b33612c400941d7394ce5254fa52520be8988bc59d11784
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.4.2
|
data/README.md
CHANGED
|
@@ -4,9 +4,9 @@ Fast host configuration tool.
|
|
|
4
4
|
|
|
5
5
|
## TODO
|
|
6
6
|
|
|
7
|
-
* [
|
|
7
|
+
* [x] Run with `sudo`
|
|
8
|
+
* [x] Commands with arguments
|
|
8
9
|
* [ ] Reading and writing files
|
|
9
|
-
* [ ] Run with `sudo`
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -55,6 +55,25 @@ runner.exec("hostname") # ["alpha001\n", "omega001\n"]
|
|
|
55
55
|
runner.exec { hostname + uptime } # ["alpha001\n2000 years\n", "omega001\2500 years\n"]
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
### Something more complex
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
public_key_path = File.expand_path("~/.ssh/id_ed25519.pub")
|
|
62
|
+
my_key = File.read(public_key_path).chomp
|
|
63
|
+
|
|
64
|
+
result = runner.exec do
|
|
65
|
+
h = hostname
|
|
66
|
+
keys = authorized_keys
|
|
67
|
+
|
|
68
|
+
if keys.include?(my_key)
|
|
69
|
+
puts "Key already in authorized_keys on host #{h}"
|
|
70
|
+
else
|
|
71
|
+
add_authorized_key my_key
|
|
72
|
+
puts "Added new key for host #{h}"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
58
77
|
## Development
|
|
59
78
|
|
|
60
79
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/TODO.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
- [x] Load session commands automatically from `lib/herd/session/commands`.
|
|
4
|
+
- [x] Extract existing `Session` command helpers (e.g., `add_authorized_key`) into the commands directory.
|
|
5
|
+
- [x] Ensure new command loading approach is covered by specs.
|
|
6
|
+
- [ ] Add explicit `logger` dependency to address net-ssh warning on Ruby 3.4.2.
|
|
7
|
+
- [ ] Document new command-extension flow with YARD annotations.
|
|
8
|
+
|
|
9
|
+
# Log
|
|
10
|
+
|
|
11
|
+
- Initialized planning file and seeded initial task list.
|
|
12
|
+
- Updated project configuration to target Ruby 3.4.2 (Gemfile, gemspec, .ruby-version, lockfile).
|
|
13
|
+
- Synced RuboCop config with Ruby 3.4.2 and confirmed clean lint run.
|
|
14
|
+
- Moved development dependencies from gemspec to Gemfile; bundle, lint, and tests still pass (with net-ssh logger warning).
|
|
15
|
+
- Fixed `Session#method_missing` to avoid extra spaces when building commands; specs now green.
|
|
16
|
+
- Implemented automatic session command loading via prepended modules, moved authorized key helpers, added YARD dependency, and expanded specs accordingly.
|
|
17
|
+
|
|
18
|
+
# Notes
|
|
19
|
+
|
|
20
|
+
- Keep command implementations in English and back them with tests.
|
data/lib/herd/host.rb
CHANGED
|
@@ -5,7 +5,7 @@ require "net/ssh"
|
|
|
5
5
|
module Herd
|
|
6
6
|
# Target host
|
|
7
7
|
class Host
|
|
8
|
-
attr_reader :host, :user, :ssh_options
|
|
8
|
+
attr_reader :host, :user, :ssh_options, :password
|
|
9
9
|
|
|
10
10
|
def initialize(host, user, port: 22, private_key_path: nil, password: nil)
|
|
11
11
|
@host = host
|
|
@@ -17,15 +17,18 @@ module Herd
|
|
|
17
17
|
else
|
|
18
18
|
@ssh_options[:password] = password
|
|
19
19
|
end
|
|
20
|
+
|
|
21
|
+
@password = password
|
|
20
22
|
end
|
|
21
23
|
|
|
22
|
-
def exec(command = nil, &
|
|
24
|
+
def exec(command = nil, &)
|
|
23
25
|
Net::SSH.start(host, user, ssh_options) do |ssh|
|
|
24
|
-
session = Herd::Session.new(ssh)
|
|
26
|
+
session = Herd::Session.new(ssh, password)
|
|
25
27
|
|
|
26
28
|
output = nil
|
|
27
29
|
output = session.send(command) if command
|
|
28
|
-
output = session.instance_exec(&
|
|
30
|
+
output = session.instance_exec(&) if block_given?
|
|
31
|
+
|
|
29
32
|
output
|
|
30
33
|
end
|
|
31
34
|
end
|
data/lib/herd/runner.rb
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Herd
|
|
4
|
+
module SessionCommands
|
|
5
|
+
# Commands for inspecting and managing authorized SSH keys.
|
|
6
|
+
module AuthorizedKeys
|
|
7
|
+
def authorized_keys
|
|
8
|
+
cat("~/.ssh/authorized_keys")&.chomp&.split("\n") || []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add_authorized_key(key)
|
|
12
|
+
touch("~/.ssh/authorized_keys")
|
|
13
|
+
chmod("600 ~/.ssh/authorized_keys")
|
|
14
|
+
echo("'#{key}' >> ~/.ssh/authorized_keys")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Herd
|
|
4
|
+
module SessionCommands
|
|
5
|
+
# Working with package managers, like apt for Ubuntu
|
|
6
|
+
module Packages
|
|
7
|
+
def install_packages(packages)
|
|
8
|
+
packages = [packages].flatten.join(" ")
|
|
9
|
+
echo %(-e '#{password}\n' | sudo -S apt install -qq -y #{packages})
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/herd/session.rb
CHANGED
|
@@ -3,37 +3,82 @@
|
|
|
3
3
|
module Herd
|
|
4
4
|
# Session for executing commands on the remote host
|
|
5
5
|
class Session
|
|
6
|
-
|
|
6
|
+
OS_COMMANDS = %i[cat chmod echo hostname touch].freeze
|
|
7
|
+
CUSTOM_COMMANDS_DIR = File.expand_path("session/commands", __dir__)
|
|
7
8
|
|
|
8
|
-
attr_reader :ssh
|
|
9
|
+
attr_reader :ssh, :password
|
|
9
10
|
|
|
10
|
-
def initialize(ssh)
|
|
11
|
+
def initialize(ssh, password = nil)
|
|
11
12
|
@ssh = ssh
|
|
13
|
+
@password = password
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
+
def method_missing(cmd, *args)
|
|
17
|
+
command_parts = [cmd.to_s]
|
|
18
|
+
command_parts.concat(args.map(&:to_s)) if args.any?
|
|
19
|
+
command = command_parts.join(" ")
|
|
20
|
+
|
|
21
|
+
run(command)
|
|
16
22
|
end
|
|
17
23
|
|
|
18
|
-
def
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
def run(command)
|
|
25
|
+
result = []
|
|
26
|
+
ssh.open_channel do |channel|
|
|
27
|
+
channel.request_pty do |ch, success|
|
|
28
|
+
raise ::Herd::CommandError, "could not obtain pty" unless success
|
|
29
|
+
|
|
30
|
+
channel_run(ch, command, result)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
ssh.loop
|
|
34
|
+
result.join
|
|
22
35
|
end
|
|
23
36
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
def respond_to_missing?(cmd)
|
|
38
|
+
OS_COMMANDS.include?(cmd) || super
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class << self
|
|
42
|
+
def load_command_modules
|
|
43
|
+
command_files.each { |file| require file }
|
|
27
44
|
|
|
28
|
-
|
|
29
|
-
|
|
45
|
+
session_command_modules.each do |mod|
|
|
46
|
+
next if self <= mod
|
|
30
47
|
|
|
31
|
-
|
|
48
|
+
prepend mod
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def command_files
|
|
55
|
+
Dir[File.join(CUSTOM_COMMANDS_DIR, "*.rb")]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def session_command_modules
|
|
59
|
+
return [] unless defined?(Herd::SessionCommands)
|
|
60
|
+
|
|
61
|
+
Herd::SessionCommands.constants
|
|
62
|
+
.sort
|
|
63
|
+
.map { |const_name| Herd::SessionCommands.const_get(const_name) }
|
|
64
|
+
.select { |value| value.is_a?(Module) }
|
|
32
65
|
end
|
|
33
66
|
end
|
|
34
67
|
|
|
35
|
-
|
|
36
|
-
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def channel_run(channel, command, result)
|
|
71
|
+
channel.exec(command) do |c, _|
|
|
72
|
+
c.on_data do |_, data|
|
|
73
|
+
result << data
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
c.on_extended_data do |_, _, data|
|
|
77
|
+
raise ::Herd::CommandError, data
|
|
78
|
+
end
|
|
79
|
+
end
|
|
37
80
|
end
|
|
38
81
|
end
|
|
39
82
|
end
|
|
83
|
+
|
|
84
|
+
Herd::Session.load_command_modules
|
data/lib/herd/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,70 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: herd-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yury Kotlyarov
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
12
|
-
- !ruby/object:Gem::Dependency
|
|
13
|
-
name: rspec
|
|
14
|
-
requirement: !ruby/object:Gem::Requirement
|
|
15
|
-
requirements:
|
|
16
|
-
- - "~>"
|
|
17
|
-
- !ruby/object:Gem::Version
|
|
18
|
-
version: '3.0'
|
|
19
|
-
type: :development
|
|
20
|
-
prerelease: false
|
|
21
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
-
requirements:
|
|
23
|
-
- - "~>"
|
|
24
|
-
- !ruby/object:Gem::Version
|
|
25
|
-
version: '3.0'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: rubocop
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - "~>"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '1.21'
|
|
33
|
-
type: :development
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '1.21'
|
|
40
|
-
- !ruby/object:Gem::Dependency
|
|
41
|
-
name: rubocop-rake
|
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - ">="
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '0'
|
|
47
|
-
type: :development
|
|
48
|
-
prerelease: false
|
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
-
requirements:
|
|
51
|
-
- - ">="
|
|
52
|
-
- !ruby/object:Gem::Version
|
|
53
|
-
version: '0'
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: rubocop-rspec
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - ">="
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: '0'
|
|
61
|
-
type: :development
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - ">="
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '0'
|
|
11
|
+
dependencies: []
|
|
68
12
|
description: |
|
|
69
13
|
Simple ruby DSL for fast host configuration. Supports Ubuntu and requires
|
|
70
14
|
SSH server running on each targets host.
|
|
@@ -74,14 +18,18 @@ executables: []
|
|
|
74
18
|
extensions: []
|
|
75
19
|
extra_rdoc_files: []
|
|
76
20
|
files:
|
|
21
|
+
- ".ruby-version"
|
|
77
22
|
- CODE_OF_CONDUCT.md
|
|
78
23
|
- LICENSE.txt
|
|
79
24
|
- README.md
|
|
80
25
|
- Rakefile
|
|
26
|
+
- TODO.md
|
|
81
27
|
- lib/herd.rb
|
|
82
28
|
- lib/herd/host.rb
|
|
83
29
|
- lib/herd/runner.rb
|
|
84
30
|
- lib/herd/session.rb
|
|
31
|
+
- lib/herd/session/commands/authorized_keys.rb
|
|
32
|
+
- lib/herd/session/commands/packages.rb
|
|
85
33
|
- lib/herd/version.rb
|
|
86
34
|
- sig/herd.rbs
|
|
87
35
|
homepage: https://github.com/yura/herd
|
|
@@ -91,6 +39,7 @@ metadata:
|
|
|
91
39
|
allowed_push_host: https://rubygems.org
|
|
92
40
|
homepage_uri: https://github.com/yura/herd
|
|
93
41
|
source_code_uri: https://github.com/yura/herd
|
|
42
|
+
rubygems_mfa_required: 'true'
|
|
94
43
|
rdoc_options: []
|
|
95
44
|
require_paths:
|
|
96
45
|
- lib
|
|
@@ -98,7 +47,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
98
47
|
requirements:
|
|
99
48
|
- - ">="
|
|
100
49
|
- !ruby/object:Gem::Version
|
|
101
|
-
version: 3.2
|
|
50
|
+
version: 3.4.2
|
|
102
51
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
52
|
requirements:
|
|
104
53
|
- - ">="
|