kanrisuru 0.7.0 → 0.8.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: bb8de477e2168c782b7cb082a6a6760fd56aa6925f1820ee80e45baff76a7b27
4
- data.tar.gz: ad21e0b9787a2e42d8626a367f11b44ff97ec27f000a6ec8f7967d7b22da066d
3
+ metadata.gz: 4f5fe692ff53ac4de87ca38181765a63cf88f0beab4e44145c780ba9af934ede
4
+ data.tar.gz: 58acc02d34aff916670ab26c9659f7e40205d31492ec5f043ea51487df33cb62
5
5
  SHA512:
6
- metadata.gz: 0cdeb2cda038612234429eb9ca172f294f60bb8bdcb0d5db2490231dfc4ab4205ae240b3f8ef8ebab41b5de6ef9d2599c7db76dd0ebe229b8b896e3a831c8805
7
- data.tar.gz: b32d4fe02fe5897a8f56d827290516ceb393db63068f9cba3a4396b79e667dd62a332013fbb6fe674cd680ccd374faff877441f92f57048d5b782e244b23ec20
6
+ metadata.gz: e2b8134ef2351a86f88286a7ed50a1f768510c75f65ecbf9d9684f376606b46ea023f1b78723ae550183c7606e230d7152614d263b19f1a31c6bf6fe0cfa2cc3
7
+ data.tar.gz: f7382ab716a20185ec071f96b6793afa7fcc1e11d32a0dd3174455cb7a5ba19d3fb61aa0fbb7d5574f26af36d983b3fae4ee9ec5757f16ef2a21edc43d5d83cd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## Kanrisuru 0.8.0 (August 18, 2021) ##
2
+ * Add last / lastb implementation in system core module.
3
+
4
+ ## Kanrisuru 0.7.3 (August 9, 2021) ##
5
+ * Fixed bug with zypper remove package, where the package names weren't being added to the linux command.
6
+ * Test case added to ensure package is removed.
7
+
8
+ ## Kanrisuru 0.7.2 (August 9, 2021) ##
9
+ * Fixed bug with the `os_method_cache` instance variable set in the namespaced instance of a host. This was causing collision issues inbetween host instances, where, hosts with the same aliased method name was getting overwritten (with a different OS), since the namespace instance variable existing on the host class definition wasn't getting reset inbetween host instantiations. Given that the `os_method_cache` is normally re-instantiated, this bug fix addresses this so that the `os_method_cache` is always defined on the host instance, ie:
10
+
11
+ ```ruby
12
+ host.instance_variable_get(:@os_method_cache)
13
+ host.instance_variable_set(:@os_method_cache, os_method_cache)
14
+ ```
15
+ This is done instead of being saved on the namespace module. With the previous bug fix of using namespaced keys, there's no way for a method to be overwritten otherwise with a global `os_method_cache`.
16
+
17
+ ## Kanrisuru 0.7.1 (August 8, 2021) ##
18
+ * Fix bug with `os_include` when caching namespace unbound methods, use the namespace in the
19
+ cache key to avoid any namespace collisions with the same method name, namely:
20
+ ```ruby
21
+ "#{namespace}.#{method_name}"
22
+ ```
23
+
1
24
  ## Kanrisuru 0.7.0 (August 8, 2021) ##
2
25
  * Simplify `FileInfo` struct for return object of `ls` command.
3
26
  * Rename `size` to `fsize` for the `OpenFile` struct to avoid method naming conflicts of the struct class.
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'date'
4
+ require 'ipaddr'
4
5
 
5
6
  module Kanrisuru
6
7
  module Core
@@ -19,6 +20,7 @@ module Kanrisuru
19
20
  os_define :linux, :kstat
20
21
 
21
22
  os_define :linux, :lsof
23
+ os_define :linux, :last
22
24
 
23
25
  os_define :linux, :uptime
24
26
 
@@ -116,6 +118,19 @@ module Kanrisuru
116
118
  :name
117
119
  )
118
120
 
121
+ SessionDetail = Struct.new(
122
+ :tty,
123
+ :login_at,
124
+ :logout_at,
125
+ :ip_address,
126
+ :success
127
+ )
128
+
129
+ LoginUser = Struct.new(
130
+ :user,
131
+ :sessions
132
+ )
133
+
119
134
  def load_env
120
135
  command = Kanrisuru::Command.new('env')
121
136
  execute_shell(command)
@@ -271,6 +286,65 @@ module Kanrisuru
271
286
  Kanrisuru::Result.new(command, &:to_i)
272
287
  end
273
288
 
289
+ def last(opts = {})
290
+ command =
291
+ if opts[:failed_attempts]
292
+ Kanrisuru::Command.new('lastb')
293
+ else
294
+ Kanrisuru::Command.new('last')
295
+ end
296
+
297
+ command.append_flag('-i')
298
+ command.append_flag('-F')
299
+ command.append_arg('-f', opts[:file])
300
+
301
+ ## Some systems only use 1 space between user and TTY field
302
+ ## Add an additional space in output formatting for simple parsing
303
+ ## logic.
304
+ command | "sed 's/ / /'"
305
+
306
+ execute_shell(command)
307
+
308
+ Kanrisuru::Result.new(command) do |cmd|
309
+ lines = cmd.to_a
310
+
311
+ mapping = {}
312
+
313
+ lines.each do |line|
314
+ next if Kanrisuru::Util.blank?(line)
315
+ next if line.include?('wtmp') || line.include?('btmp')
316
+
317
+ line = line.gsub(' still logged in', '- still logged in') if line.include?('still logged in')
318
+
319
+ values = line.split(/\s{2,}/, 4)
320
+ user = values[0]
321
+ tty = values[1]
322
+ ip = IPAddr.new(values[2])
323
+
324
+ date_range = values[3]
325
+ login, logout = date_range.split(' - ')
326
+
327
+ login = parse_last_date(login) if login
328
+
329
+ logout = parse_last_date(logout) if logout
330
+
331
+ detail = SessionDetail.new
332
+ detail.tty = tty
333
+ detail.ip_address = ip
334
+ detail.login_at = login
335
+ detail.logout_at = logout
336
+
337
+ detail.success = !Kanrisuru::Util.present?(opts[:failed_attemps])
338
+
339
+ mapping[user] = LoginUser.new(user, []) unless mapping.key?(user)
340
+
341
+ mapping[user].sessions << detail
342
+ end
343
+
344
+ mapping.values
345
+ end
346
+ end
347
+
274
348
  def ps(opts = {})
275
349
  group = opts[:group]
276
350
  user = opts[:user]
@@ -567,6 +641,19 @@ module Kanrisuru
567
641
  line.split(char, 2)[1]
568
642
  end
569
643
 
644
+ def parse_last_date(string)
645
+ tokens = string.split
646
+
647
+ return if tokens.length < 4
648
+
649
+ month_abbr = tokens[1]
650
+ day = tokens[2]
651
+ timestamp = tokens[3]
652
+ year = tokens[4]
653
+
654
+ DateTime.parse("#{day} #{month_abbr} #{year} #{timestamp}")
655
+ end
656
+
570
657
  def parse_policy_abbr(value)
571
658
  case value
572
659
  when '-'
@@ -714,6 +714,9 @@ module Kanrisuru
714
714
  zypper_package_type_opt(command, opts)
715
715
  zypper_solver_opts(command, opts)
716
716
 
717
+ packages = Kanrisuru::Util.string_join_array(opts[:packages], ' ')
718
+ command << packages
719
+
717
720
  execute_shell(command)
718
721
  Kanrisuru::Result.new(command)
719
722
  end
@@ -8,7 +8,6 @@ module Kanrisuru
8
8
  def self.extended(base)
9
9
  base.instance_variable_set(:@os_method_properties, {})
10
10
  base.instance_variable_set(:@os_methods, Set.new)
11
- base.instance_variable_set(:@os_method_cache, {})
12
11
  end
13
12
 
14
13
  def os_define(os_name, method_name, options = {})
@@ -102,12 +101,6 @@ module Kanrisuru
102
101
  include_methods = (public_methods + protected_methods + private_methods).flatten
103
102
 
104
103
  include_method_bindings = proc do
105
- define_method 'os_method_cache' do
106
- @os_method_cache ||= {}
107
- end
108
-
109
- private :os_method_cache
110
-
111
104
  include_methods.each do |method_name|
112
105
  define_method method_name do |*args, &block|
113
106
  unbound_method = mod.instance_method(method_name)
@@ -144,10 +137,11 @@ module Kanrisuru
144
137
  ## defined with the methods added.
145
138
  if Kanrisuru::Remote::Host.instance_variable_defined?("@#{namespace}")
146
139
  namespace_class = Kanrisuru::Remote::Host.const_get(Kanrisuru::Util.camelize(namespace))
147
- namespace_instance = instance_variable_get("@#{namespace}")
140
+ namespace_instance = Kanrisuru::Remote::Host.instance_variable_get("@#{namespace}")
148
141
  else
149
142
  namespace_class = Kanrisuru::Remote::Host.const_set(Kanrisuru::Util.camelize(namespace), Class.new)
150
143
  namespace_instance = Kanrisuru::Remote::Host.instance_variable_set("@#{namespace}", namespace_class.new)
144
+
151
145
  class_eval do
152
146
  define_method namespace do
153
147
  namespace_instance.instance_variable_set(:@host, self)
@@ -168,11 +162,12 @@ module Kanrisuru
168
162
  define_method method_name do |*args, &block|
169
163
  unbound_method = nil
170
164
 
171
- if os_method_cache.key?(method_name)
172
- unbound_method = os_method_cache[method_name]
173
- else
174
- host = namespace_instance.instance_variable_get(:@host)
165
+ host = namespace_instance.instance_variable_get(:@host)
166
+ os_method_cache = host.instance_variable_get(:@os_method_cache) || {}
175
167
 
168
+ if os_method_cache.key?("#{namespace}.#{method_name}")
169
+ unbound_method = os_method_cache["#{namespace}.#{method_name}"]
170
+ else
176
171
  ## Find the correct method to resolve based on the OS for the remote host.
177
172
  defined_method_name = host.resolve_os_method_name(os_method_properties, method_name)
178
173
  unless defined_method_name
@@ -185,7 +180,8 @@ module Kanrisuru
185
180
 
186
181
  ## Cache the unbound method on this host instance for faster resolution on
187
182
  ## the next invocation of this method
188
- os_method_cache[method_name] = unbound_method
183
+ os_method_cache["#{namespace}.#{method_name}"] = unbound_method
184
+ host.instance_variable_set(:@os_method_cache, os_method_cache)
189
185
  end
190
186
 
191
187
  ## Bind the method to host instance and
@@ -197,11 +193,12 @@ module Kanrisuru
197
193
  define_method method_name do |*args, &block|
198
194
  unbound_method = nil
199
195
 
196
+ host = self
197
+ os_method_cache = host.instance_variable_get(:@os_method_cache) || {}
198
+
200
199
  if os_method_cache.key?(method_name)
201
200
  unbound_method = os_method_cache[method_name]
202
201
  else
203
- host = self
204
-
205
202
  ## Find the correct method to resolve based on the OS for the remote host.
206
203
  defined_method_name = host.resolve_os_method_name(os_method_properties, method_name)
207
204
  raise NoMethodError, "undefined method `#{method_name}' for #{self.class}" unless defined_method_name
@@ -213,6 +210,7 @@ module Kanrisuru
213
210
  ## Cache the unbound method on this host instance for faster resolution on
214
211
  ## the next invocation of this method
215
212
  os_method_cache[method_name] = unbound_method
213
+ host.instance_variable_set(:@os_method_cache, os_method_cache)
216
214
  end
217
215
 
218
216
  ## Bind the method to host instance and
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kanrisuru
4
- VERSION = '0.7.0'
4
+ VERSION = '0.8.0'
5
5
  end
@@ -96,6 +96,21 @@ RSpec.describe Kanrisuru::Core::System do
96
96
  expect(result.cpus.length).to eq(host.cpu.cores)
97
97
  end
98
98
 
99
+ it 'gets login details' do
100
+ host.su('root')
101
+
102
+ result = host.last
103
+ expect(result).to be_success
104
+ end
105
+
106
+ it 'gets failed login attempts' do
107
+ host.su('root')
108
+
109
+ result = host.last(failed_attempts: true)
110
+ puts result.data
111
+ expect(result).to be_success
112
+ end
113
+
99
114
  it 'gets process details' do
100
115
  result = host.ps
101
116
 
@@ -40,6 +40,12 @@ RSpec.describe Kanrisuru::Core::Zypper do
40
40
  expect(result).to be_success
41
41
  end
42
42
 
43
+ it 'removes a package' do
44
+ host.su('root')
45
+ result = host.zypper('remove', packages: ['ffmpeg'])
46
+ expect(result).to be_success
47
+ end
48
+
43
49
  it 'lists updates' do
44
50
  result = host.zypper('list-updates')
45
51
  expect(result).to be_success
@@ -40,18 +40,66 @@ module Kanrisuru
40
40
  a - b
41
41
  end
42
42
  end
43
+
44
+ module TestAliasNames
45
+ extend Kanrisuru::OsPackage::Define
46
+
47
+ os_define :fedora, :output_fedora, alias: :output
48
+ os_define :debian, :output_debian, alias: :output
49
+ os_define :sles, :output_sles, alias: :output
50
+
51
+ def output_debian
52
+ 'debian'
53
+ end
54
+
55
+ def output_fedora
56
+ 'fedora'
57
+ end
58
+
59
+ def output_sles
60
+ 'sles'
61
+ end
62
+ end
63
+
64
+ module TestAliasNamesNamespace
65
+ extend Kanrisuru::OsPackage::Define
66
+
67
+ os_define :fedora, :output_fedora, alias: :output
68
+ os_define :debian, :output_debian, alias: :output
69
+ os_define :sles, :output_sles, alias: :output
70
+
71
+ def output_debian
72
+ 'debian'
73
+ end
74
+
75
+ def output_fedora
76
+ 'fedora'
77
+ end
78
+
79
+ def output_sles
80
+ 'sles'
81
+ end
82
+ end
43
83
  end
44
84
 
45
85
  module Kanrisuru
46
86
  module Remote
47
87
  class Host
48
88
  os_include Kanrisuru::TestInclude
89
+
90
+ os_include Kanrisuru::TestAliasNames
91
+ os_include Kanrisuru::TestAliasNamesNamespace, namespace: :alias
92
+
49
93
  os_include Kanrisuru::TestNamespaceAdditions, namespace: :asdf
50
94
  os_include Kanrisuru::TestNamespace, namespace: :asdf
51
95
  end
52
96
 
53
97
  class Cluster
54
98
  os_collection Kanrisuru::TestInclude
99
+
100
+ os_collection Kanrisuru::TestAliasNames
101
+ os_collection Kanrisuru::TestAliasNamesNamespace, namespace: :alias
102
+
55
103
  os_collection Kanrisuru::TestNamespaceAdditions, namespace: :asdf
56
104
  os_collection Kanrisuru::TestNamespace, namespace: :asdf
57
105
  end
@@ -94,6 +142,52 @@ RSpec.describe Kanrisuru::OsPackage do
94
142
  expect(cluster.asdf.tester).to be_instance_of(Array)
95
143
 
96
144
  host.disconnect
145
+ host2.disconnect
146
+ cluster.disconnect
147
+ end
148
+
149
+ it 'includes the correct alias named method' do
150
+ host1 = Kanrisuru::Remote::Host.new(host: 'ubuntu-host', username: 'ubuntu', keys: ['~/.ssh/id_rsa'])
151
+ host2 = Kanrisuru::Remote::Host.new(host: 'centos-host', username: 'centos', keys: ['~/.ssh/id_rsa'])
152
+ host3 = Kanrisuru::Remote::Host.new(host: 'opensuse-host', username: 'opensuse', keys: ['~/.ssh/id_rsa'])
153
+
154
+ cluster = Kanrisuru::Remote::Cluster.new([host1, host2, host3])
155
+
156
+ expect(host1).to respond_to(:output)
157
+ expect(host2).to respond_to(:output)
158
+ expect(host3).to respond_to(:output)
159
+ expect(host1.output).to eq('debian')
160
+ expect(host2.output).to eq('fedora')
161
+ expect(host3.output).to eq('sles')
162
+
163
+ expect(cluster).to respond_to(:output)
164
+ expect(cluster.output).to eq([
165
+ { host: 'ubuntu-host', result: 'debian' },
166
+ { host: 'centos-host', result: 'fedora' },
167
+ { host: 'opensuse-host', result: 'sles' }
168
+ ])
169
+
170
+ expect(host1).to respond_to(:alias)
171
+ expect(host2).to respond_to(:alias)
172
+ expect(host3).to respond_to(:alias)
173
+ expect(host1.alias).to respond_to(:output)
174
+ expect(host2.alias).to respond_to(:output)
175
+ expect(host3.alias).to respond_to(:output)
176
+ expect(host1.alias.output).to eq('debian')
177
+ expect(host2.alias.output).to eq('fedora')
178
+ expect(host3.alias.output).to eq('sles')
179
+
180
+ expect(cluster).to respond_to(:alias)
181
+ expect(cluster.alias).to respond_to(:output)
182
+ expect(cluster.alias.output).to eq([
183
+ { host: 'ubuntu-host', result: 'debian' },
184
+ { host: 'centos-host', result: 'fedora' },
185
+ { host: 'opensuse-host', result: 'sles' }
186
+ ])
187
+
188
+ host1.disconnect
189
+ host2.disconnect
190
+ host3.disconnect
97
191
  cluster.disconnect
98
192
  end
99
193
  end
data/spec/spec_helper.rb CHANGED
@@ -4,7 +4,6 @@ require 'simplecov'
4
4
  SimpleCov.start
5
5
 
6
6
  require 'kanrisuru'
7
-
8
7
  require_relative 'helper/test_hosts'
9
8
 
10
9
  Kanrisuru.logger.level = Logger::WARN
@@ -86,5 +86,17 @@ RSpec.describe Kanrisuru::Core::System do
86
86
  :inode,
87
87
  :name
88
88
  )
89
+ expect(Kanrisuru::Core::System::SessionDetail.new).to respond_to(
90
+ :tty,
91
+ :login_at,
92
+ :logout_at,
93
+ :ip_address,
94
+ :success
95
+ )
96
+
97
+ expect(Kanrisuru::Core::System::LoginUser.new).to respond_to(
98
+ :user,
99
+ :sessions
100
+ )
89
101
  end
90
102
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kanrisuru
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Mammina
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-08 00:00:00.000000000 Z
11
+ date: 2021-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec