racf 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.travis.yml +18 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +40 -0
- data/README.rdoc +56 -0
- data/Rakefile +9 -0
- data/TODO.txt +5 -0
- data/config/racf.yml.sample +27 -0
- data/lib/racf.rb +78 -0
- data/lib/racf/client.rb +138 -0
- data/lib/racf/commands/abstract_command.rb +13 -0
- data/lib/racf/commands/listgrp.rb +189 -0
- data/lib/racf/commands/listgrp/group_members_parser.rb +104 -0
- data/lib/racf/commands/listuser.rb +112 -0
- data/lib/racf/commands/rlist.rb +208 -0
- data/lib/racf/commands/search.rb +31 -0
- data/lib/racf/pagers/cached_ispf_pager.rb +91 -0
- data/lib/racf/pagers/ispf_pager.rb +57 -0
- data/lib/racf/s3270.rb +136 -0
- data/lib/racf/session.rb +149 -0
- data/lib/racf/version.rb +3 -0
- data/racf.gemspec +16 -0
- data/script/ci +3 -0
- data/spec/fixtures/config/racf.yml +9 -0
- data/spec/fixtures/listgrp/multiple_groups_multiple_members.txt +26 -0
- data/spec/fixtures/listgrp/multiple_members.txt +10 -0
- data/spec/fixtures/listgrp/no_members.txt +4 -0
- data/spec/fixtures/listgrp/not_found_groups.txt +21 -0
- data/spec/fixtures/listgrp/one_group.txt +7 -0
- data/spec/fixtures/listgrp/one_group_with_members.txt +13 -0
- data/spec/fixtures/listgrp/one_member.txt +7 -0
- data/spec/fixtures/listuser/all_users.txt +45 -0
- data/spec/fixtures/listuser/just_users_not_found.txt +3 -0
- data/spec/fixtures/listuser/one_user.txt +47 -0
- data/spec/fixtures/listuser/some_not_found_users.txt +88 -0
- data/spec/fixtures/racf_cache_dump.yml +9 -0
- data/spec/fixtures/rlist/gims.txt +135 -0
- data/spec/fixtures/rlist/gims_with_no_tims.txt +135 -0
- data/spec/fixtures/rlist/gims_with_not_found.txt +89 -0
- data/spec/fixtures/rlist/just_one_not_found.txt +1 -0
- data/spec/fixtures/rlist/multiple_not_found.txt +3 -0
- data/spec/fixtures/rlist/rlist_success.txt +50 -0
- data/spec/fixtures/rlist/tims_without_users.txt +119 -0
- data/spec/fixtures/search/gims.txt +30 -0
- data/spec/fixtures/search/tims.txt +30 -0
- data/spec/fixtures/session/screen_with_bottom_menu.txt +31 -0
- data/spec/fixtures/session/screen_with_top_and_bottom_menu.txt +47 -0
- data/spec/fixtures/session/screen_with_top_menu.txt +29 -0
- data/spec/fixtures/session/screen_without_menu.txt +13 -0
- data/spec/racf/client_spec.rb +155 -0
- data/spec/racf/commands/listgrp/group_members_parser_spec.rb +82 -0
- data/spec/racf/commands/listgrp_spec.rb +303 -0
- data/spec/racf/commands/listuser_spec.rb +123 -0
- data/spec/racf/commands/rlist_spec.rb +257 -0
- data/spec/racf/commands/search_spec.rb +66 -0
- data/spec/racf/pagers/cached_ispf_pager_spec.rb +212 -0
- data/spec/racf/pagers/ispf_pager_spec.rb +59 -0
- data/spec/racf/session_spec.rb +114 -0
- data/spec/racf_spec.rb +106 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/helpers.rb +5 -0
- metadata +162 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# http://about.travis-ci.org/docs/user/getting-started/
|
2
|
+
#
|
3
|
+
# use before_install to install any missing packages you require
|
4
|
+
# before_install: sudo apt-get install my-special-packages
|
5
|
+
#
|
6
|
+
# use before_script to setup any DB's you need, or start xvfb
|
7
|
+
# before_script: mysql -e 'create database myapp_test;'
|
8
|
+
#
|
9
|
+
# override script if you have a special script to run
|
10
|
+
# (default is bundle exec rake)
|
11
|
+
# script: bundle exec rspec
|
12
|
+
source_key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBNnZ5bVk3bjRXRlBPYnNSb2JnZnlFVXhkYjZYTWtoSkh0bkwwY2NUOHZXUnE3VTVJCkM2TlpTRHlhcFdscGxyL3MwMEJaOUxUcFNmMUl5Q1ZQUTVtTk1CS041cDd2RTQ2NVJucWtaMzd2OWk2dFdDb2IKQmFQeWsrRlZrbGE3amJ4bElORG9odGhzcVlxN1YxRzB1a1ovWHBiSXlCbElIWW4zRk9RTFJldWpZQUpxalFKMgplRnRhQVNRZFJJNUpBcHcrampBUmhzaEJ1a2ZmNnRob3IvMkppajlqOGplYmpjZjdkSjBNUkdDa21aL2duclhDCjNCWjl2ZW4ydWJEWEVHSEp3ZXJDd29EajhHRzBMcU5PdXZUVVlnZG9mNkEzSHRYOWlzWnYwZElNUTIrTE0yYWcKTWV1S1BjRDcwY0d5bjZYREVZMlIyd2lhUGx3ckhGT2FCUnBEU3dJREFRQUJBb0lCQUJVajliUXpIdXlUWFpjSgpoSHVocTExekNWVHFEYVYyajQwU2VudGh4WHNrZFpvejJMZHpVcXoxQnRTcXp4MEkxejJLSkkybldQV1hHOTBsCnZpUE94S3oyZmwycEhza2JwZjk1T1NFMmdsQWJrdXpEblBxODdTM3dyOG9pazIwRTdmUXQxejJLYXZ3MXh2VHMKSE41RlNXQXhJSThmOXlUeExKRnNrcmNQby9zWEVHWHhyR3YyeEhQeDBYYUEzM3JwajQwMUZhVnJHTC9RM24yRQo0L1JEbnE1blkrQzdQOUJqWUFBVHMzb0R5UEkxeTE3MnUrc3p4TVNNb2VpZzRVcHVaQlp5czRBYzE4RktCUXM5CitxNUk4RnVvaU83dVVieWlkcUozc3ZMdkh3NCtnOTFqV1VpNkVVL1pGZVBzV0UvaUhyMjVDSGVZbGltNjdHTksKcE9wVkR3RUNnWUVBL2tCSHlnVnNoRUYyWW5GdldmVythdTJ3Q0dHNitpeDBRZTI4RjNHZGlYMUtPRHYrVElDUgpBSDgzaFJLS3hiaHNaRTI3RzZyd2JMakRMajNHKy9HUVlLRnlPM0JmcWpTalV5QnhmSVpTNjYwKzVWUWVhQWJOCkJFcjUwWE5Yd0FoanViRWJ2ZUkra0RuNENHb0dCMzQvV2NDZFhyRXRmOVJwYVFyWkR1VlZRN0VDZ1lFQTdKcHkKVWoxTlRCUXBKeTlxWmE1WFN5dVdmV1pTZTRmWjhXeDI2YTZXd1JkMlNaUTRseVN5Umk4K2VGdU16RFdwc09oVgppT05hM1prUVJhYUVXRjhYby9lSkhmTkpoanQrTU9SaGY3S1FtYWc5WHhGODZzRURueElGV1hxR0JYd2JXNVlnCk41VlpMUDRmaWtscWpSTU5qR2ZmbXY2OCt3MG9WUk9hMXFHWUlic0NnWUVBNEIxM2FudTNlU2xmR2syVmN2M3MKbU1MbDNhMlFMTUFNeHFTeG5SUzRZaDUvMHV3SE1CWlFPdGpvN3JNMmdpMGIxcHF5S1NSWUErNGxsbGc4VTQ5Twp6ZTdpQzhUMWZzb2hnYi9pYVhyYUV3YkduMDJ6ODh5eTRXclpwU2dBSExVSWV3SEVTMi9uNkNoQkcrR2hhTzkvCkZqVjBRcWo1UzJuSWRTQnJ6dmFXWHpFQ2dZQWdwNHhCcDI1RW9yK3ZSYzhFYTVSbXJvUmRtRUtvQSs3amNCblYKVktBLzFCSWlRNCt2NUlPcVJoajBHWWFNSkpmZjc2RG1mS0pzMVJRMjJLMkpXTTUxZGRONXk3c0pDS3I0Nm53KwpXSkcyYzA3TkVTZlJhb1FxYngxSDVTNGNFYTNnN1E1VFBZeUtOaVI2UEhtMU1Mejg5TlVhbWkvUTRsYi9ydTMrCjAxeWd3d0tCZ0hqRU5FOWlFejJlc0F4MWxFWGoyUGRGVE12VmxyeVpWbjZjSmJlbVU2R1JvYUFQdno5MWk5eTMKU3NUYVRMMnBRZ0x4R014OCtOTXlFRnNYRzY2RnA0RWxKQVRxc05Fb3V3UVRGNG54ZXlMRDZSMUF0VFlyeEZ5NgpVbnoxOHFKcTZTeTE5UDM0TDNiYUg4L3grS2lCcVBuN1ZCMHZsV2pmcG5JRnpZOTl5M0NvCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
|
13
|
+
notifications:
|
14
|
+
campfire: "autoseg:48d4106f85af3071772752d83f7c0ef0160d89e4@451526"
|
15
|
+
language: ruby
|
16
|
+
script: script/ci
|
17
|
+
rvm:
|
18
|
+
- 1.8.7
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
racf (0.6.0)
|
5
|
+
state_machine (~> 1.1.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
awesome_print (1.0.1)
|
11
|
+
columnize (0.3.5)
|
12
|
+
diff-lcs (1.1.3)
|
13
|
+
linecache (0.46)
|
14
|
+
rbx-require-relative (> 0.0.4)
|
15
|
+
rake (0.9.2.2)
|
16
|
+
rbx-require-relative (0.0.5)
|
17
|
+
rspec (2.8.0)
|
18
|
+
rspec-core (~> 2.8.0)
|
19
|
+
rspec-expectations (~> 2.8.0)
|
20
|
+
rspec-mocks (~> 2.8.0)
|
21
|
+
rspec-core (2.8.0)
|
22
|
+
rspec-expectations (2.8.0)
|
23
|
+
diff-lcs (~> 1.1.2)
|
24
|
+
rspec-mocks (2.8.0)
|
25
|
+
ruby-debug (0.10.4)
|
26
|
+
columnize (>= 0.1)
|
27
|
+
ruby-debug-base (~> 0.10.4.0)
|
28
|
+
ruby-debug-base (0.10.4)
|
29
|
+
linecache (>= 0.3)
|
30
|
+
state_machine (1.1.2)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
awesome_print
|
37
|
+
racf!
|
38
|
+
rake
|
39
|
+
rspec
|
40
|
+
ruby-debug
|
data/README.rdoc
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
== RACF
|
2
|
+
|
3
|
+
This gem is a Ruby wrapper around the around IBM's Resource Access Control
|
4
|
+
Facility (RACF). RACF It is a security system that provides access control
|
5
|
+
and auditing functionality for the z/OS and z/VM operating systems.
|
6
|
+
|
7
|
+
Yes, we're talking about using Ruby in order to connect to a mainframe!!!
|
8
|
+
|
9
|
+
After the mainframe fear passes, let's talk a bit more. (...)
|
10
|
+
|
11
|
+
|
12
|
+
== How to install?
|
13
|
+
bundle
|
14
|
+
bundle exec rake install
|
15
|
+
|
16
|
+
|
17
|
+
== How to run the specs?
|
18
|
+
bundle exec rake
|
19
|
+
|
20
|
+
|
21
|
+
== How the gem connect to a mainframe?
|
22
|
+
|
23
|
+
The way the RACF gem connects to the mainframe is through a terminal emulator
|
24
|
+
called S3270 (http://x3270.bgp.nu/s3270-man.html). S3270 opens a telnet
|
25
|
+
connection with the mainframe. After that, it opens a socket on which we can
|
26
|
+
open a telnet connection. It's through that last connection that we use s3270
|
27
|
+
to communicate with the mainframe.
|
28
|
+
|
29
|
+
So, it's something like that:
|
30
|
+
|
31
|
+
mainframe <=== telnet ===> s3270 (terminal emulator) <=== telnet ===> RACF Gem
|
32
|
+
|
33
|
+
|
34
|
+
== Ok, but, how can I use that &*%@@!%&* gem ???
|
35
|
+
|
36
|
+
You can run a RACF command as simple as that:
|
37
|
+
|
38
|
+
client = Racf::Client.new(:user_id => "mainframe_user_id",
|
39
|
+
:password => "mainframe_user_password",
|
40
|
+
:server_address => "192.168.0.1")
|
41
|
+
|
42
|
+
client.start_session do |c|
|
43
|
+
users = c.listuser("AJ00042")
|
44
|
+
puts users
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
== What's next?
|
50
|
+
|
51
|
+
Besides Ruby, the only thing you need to really use the power of that gem
|
52
|
+
is a big, big, really big client who owns a mainframe!!!
|
53
|
+
|
54
|
+
But, if you're trying that in your home and you don't have a mainframe in
|
55
|
+
your bedroom, you should give Hercules a try (http://www.hercules-390.org/).
|
56
|
+
|
data/Rakefile
ADDED
data/TODO.txt
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
development:
|
2
|
+
user_id: "user"
|
3
|
+
password: "password"
|
4
|
+
server_address: "127.0.0.1"
|
5
|
+
server_port: 3270
|
6
|
+
script_port: 3003
|
7
|
+
caching: false
|
8
|
+
dump_file: "racf_cache_dump.yml"
|
9
|
+
|
10
|
+
test:
|
11
|
+
user_id: "user"
|
12
|
+
password: "password"
|
13
|
+
server_address: "127.0.0.1"
|
14
|
+
server_port: 3270
|
15
|
+
script_port: 3003
|
16
|
+
caching: false
|
17
|
+
dump_file: "racf_cache_dump.yml"
|
18
|
+
|
19
|
+
production:
|
20
|
+
user_id: "user"
|
21
|
+
password: "password"
|
22
|
+
server_address: "127.0.0.1"
|
23
|
+
server_port: 3270
|
24
|
+
script_port: 3003
|
25
|
+
caching: false
|
26
|
+
dump_file: "racf_cache_dump.yml"
|
27
|
+
|
data/lib/racf.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
|
4
|
+
require "fileutils"
|
5
|
+
require "logger"
|
6
|
+
require "pathname"
|
7
|
+
|
8
|
+
module Racf
|
9
|
+
class << self
|
10
|
+
def root
|
11
|
+
@_root ||=
|
12
|
+
if defined?(Rails)
|
13
|
+
Rails.root
|
14
|
+
else
|
15
|
+
Pathname.new(File.expand_path("../..", __FILE__))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def logger
|
20
|
+
@logger ||= default_logger
|
21
|
+
end
|
22
|
+
attr_writer :logger
|
23
|
+
|
24
|
+
def env
|
25
|
+
@_env ||= ENV['RAILS_ENV'] || ENV['RACF_ENV'] || "development"
|
26
|
+
end
|
27
|
+
|
28
|
+
def env=(environment)
|
29
|
+
@_env = environment
|
30
|
+
end
|
31
|
+
|
32
|
+
def config
|
33
|
+
@config ||= symbolize_keys(load_config[env])
|
34
|
+
end
|
35
|
+
attr_writer :config
|
36
|
+
|
37
|
+
def config_file_path
|
38
|
+
@config_file_path ||= root.join("config", "racf.yml")
|
39
|
+
end
|
40
|
+
attr_writer :config_file_path
|
41
|
+
|
42
|
+
def dump_file_path
|
43
|
+
@dump_file_path ||= root.join("tmp", config[:dump_file] || "racf_cache_dump.yml")
|
44
|
+
end
|
45
|
+
attr_writer :dump_file_path
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def load_config
|
50
|
+
YAML.load_file(config_file_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
def default_logger
|
54
|
+
create_log_dir
|
55
|
+
|
56
|
+
log_path = default_log_dir.join("racf.log")
|
57
|
+
logger = Logger.new(log_path)
|
58
|
+
logger.formatter = Logger::Formatter.new
|
59
|
+
logger
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_log_dir
|
63
|
+
FileUtils.mkdir_p(default_log_dir)
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_log_dir
|
67
|
+
root.join("log")
|
68
|
+
end
|
69
|
+
|
70
|
+
def symbolize_keys(hash)
|
71
|
+
return {} unless hash
|
72
|
+
|
73
|
+
h = {}
|
74
|
+
hash.each_pair { |k, v| h[k.to_sym] = v }
|
75
|
+
h
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/racf/client.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
Dir["#{File.dirname(__FILE__)}/commands/*.rb"].each { |file_path| require file_path }
|
2
|
+
require 'racf/session'
|
3
|
+
require 'racf/pagers/ispf_pager'
|
4
|
+
require 'racf/pagers/cached_ispf_pager'
|
5
|
+
|
6
|
+
module Racf
|
7
|
+
# That class is intended to be "the" API for clients of the
|
8
|
+
# RACF gem. You can use it to open a connection with a mainframe
|
9
|
+
# run some RACF commands and then close the connection.
|
10
|
+
#
|
11
|
+
class Client
|
12
|
+
COMMANDS = %w(listgrp listuser rlist search)
|
13
|
+
|
14
|
+
attr_accessor :user_id, :password, :server_address, :server_port, :script_port,
|
15
|
+
:caching, :verbose, :session, :telnet_timeout
|
16
|
+
|
17
|
+
def initialize(settings={})
|
18
|
+
settings = Racf.config.merge(settings)
|
19
|
+
|
20
|
+
@user_id = settings[:user_id]
|
21
|
+
@password = settings[:password]
|
22
|
+
@server_address = settings[:server_address]
|
23
|
+
@server_port = settings[:server_port]
|
24
|
+
@script_port = settings[:script_port]
|
25
|
+
@telnet_timeout = settings[:telnet_timeout]
|
26
|
+
@caching = settings[:caching].nil? ? true : settings[:caching]
|
27
|
+
@verbose = settings[:verbose].nil? ? false : settings[:verbose]
|
28
|
+
|
29
|
+
@session = settings[:session] || create_session
|
30
|
+
|
31
|
+
load_pagers
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_session
|
35
|
+
session.start
|
36
|
+
|
37
|
+
if block_given?
|
38
|
+
begin
|
39
|
+
yield self
|
40
|
+
rescue Exception => exception
|
41
|
+
Racf.logger.error exception.message
|
42
|
+
Racf.logger.error exception.backtrace.join("\n")
|
43
|
+
raise
|
44
|
+
ensure
|
45
|
+
finish_session
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def finish_session
|
51
|
+
session.finish
|
52
|
+
end
|
53
|
+
|
54
|
+
# we should deprecate this api, in favor to config it globally
|
55
|
+
def logger=(logger)
|
56
|
+
Racf.logger = logger
|
57
|
+
end
|
58
|
+
|
59
|
+
COMMANDS.each do |command_method_name|
|
60
|
+
define_method(command_method_name) do |*args| # def listgrp(*args)
|
61
|
+
command_class = command(command_method_name) # command_class = Racf::Commands::Listgrp
|
62
|
+
#
|
63
|
+
@pagers[command_class].run(*args) # @pagers[command_class].run(*args)
|
64
|
+
end # end
|
65
|
+
end
|
66
|
+
|
67
|
+
# we should deprecate this api, in favor to config it globally
|
68
|
+
def logger=(logger)
|
69
|
+
Racf.logger = logger
|
70
|
+
end
|
71
|
+
|
72
|
+
def dump_cache
|
73
|
+
File.open(Racf.dump_file_path, "w") { |f| YAML.dump(cache, f) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def load_cache
|
77
|
+
self.cache = YAML.load_file(Racf.dump_file_path)
|
78
|
+
rescue StandardError
|
79
|
+
Racf.logger.warn "Could not load cache file! Running with empty cache."
|
80
|
+
end
|
81
|
+
|
82
|
+
def cache=(serialized_cache)
|
83
|
+
@pagers.each do |command_class, pager|
|
84
|
+
if pager.respond_to? :cache=
|
85
|
+
pager.cache = serialized_cache[command_class.to_s]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def cache
|
91
|
+
cache_dump = {}
|
92
|
+
|
93
|
+
@pagers.each do |command_class, pager|
|
94
|
+
if pager.respond_to? :cache
|
95
|
+
cache_dump[command_class.to_s] = pager.cache
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
cache_dump
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def create_session
|
105
|
+
Session.new(
|
106
|
+
:user_id => user_id,
|
107
|
+
:password => password,
|
108
|
+
:server_address => server_address,
|
109
|
+
:server_port => server_port,
|
110
|
+
:script_port => script_port,
|
111
|
+
:verbose => verbose,
|
112
|
+
:telnet_timeout => telnet_timeout
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
def load_pagers
|
117
|
+
@pagers = {}
|
118
|
+
|
119
|
+
COMMANDS.each do |command_method_name|
|
120
|
+
command_class = command(command_method_name)
|
121
|
+
|
122
|
+
@pagers[command_class] ||= pager_class.new(command_class.new(session))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def pager_class
|
127
|
+
if caching
|
128
|
+
Pagers::CachedIspfPager
|
129
|
+
else
|
130
|
+
Pagers::IspfPager
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def command(command_method_name)
|
135
|
+
Racf::Commands.const_get("#{command_method_name.capitalize}")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'racf/commands/abstract_command'
|
2
|
+
require 'racf/commands/listgrp/group_members_parser'
|
3
|
+
|
4
|
+
require 'state_machine'
|
5
|
+
|
6
|
+
module Racf
|
7
|
+
module Commands
|
8
|
+
class Listgrp < AbstractCommand
|
9
|
+
GROUP_CLUE = /INFORMATION FOR GROUP|NAME NOT FOUND IN RACF DATA SET/
|
10
|
+
|
11
|
+
state_machine :state, :initial => :nothing_processed do
|
12
|
+
state :nothing_processed, :name_processed, :superior_group_and_owner_processed,
|
13
|
+
:description_processed, :subgroups_processed,
|
14
|
+
:members_processed, :group_processed
|
15
|
+
|
16
|
+
event :process_name do
|
17
|
+
transition [:nothing_processed, :group_processed] => :name_processed
|
18
|
+
end
|
19
|
+
|
20
|
+
event :process_superior_group_and_owner do
|
21
|
+
transition :name_processed => :superior_group_and_owner_processed
|
22
|
+
end
|
23
|
+
|
24
|
+
event :process_description do
|
25
|
+
transition :superior_group_and_owner_processed => :description_processed
|
26
|
+
end
|
27
|
+
|
28
|
+
event :process_subgroups do
|
29
|
+
transition :description_processed => :subgroups_processed
|
30
|
+
end
|
31
|
+
|
32
|
+
event :finish_group_parsing do
|
33
|
+
transition :subgroups_processed => :group_processed
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(session)
|
38
|
+
@current_line = nil
|
39
|
+
@current_group = {}
|
40
|
+
@members_parser = Listgrp::GroupMembersParser.new
|
41
|
+
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def run(*args)
|
46
|
+
@groups = {}
|
47
|
+
@current_line = nil
|
48
|
+
|
49
|
+
groups_names = extract_groups_name(args)
|
50
|
+
command = "LISTGRP (#{groups_names})"
|
51
|
+
raw_output = @session.run_command(command)
|
52
|
+
log_number_of_groups(raw_output)
|
53
|
+
|
54
|
+
@group_index = 1
|
55
|
+
|
56
|
+
@number_of_lines = raw_output.lines.to_a.size
|
57
|
+
@line_number = 0
|
58
|
+
|
59
|
+
raw_output.each_line do |line|
|
60
|
+
@current_line = line.strip
|
61
|
+
@line_number += 1
|
62
|
+
|
63
|
+
group_parsed = catch(:group_parsed) do
|
64
|
+
case state_name
|
65
|
+
when :nothing_processed, :group_processed
|
66
|
+
process_name
|
67
|
+
when :name_processed
|
68
|
+
process_superior_group_and_owner
|
69
|
+
when :superior_group_and_owner_processed
|
70
|
+
process_description
|
71
|
+
when :description_processed
|
72
|
+
process_subgroups
|
73
|
+
when :subgroups_processed
|
74
|
+
@current_group[:members] ||= {}
|
75
|
+
@members_parser ||= Listgrp::GroupMembersParser.new
|
76
|
+
|
77
|
+
process_members unless next_group?
|
78
|
+
finish_group_parsing if members_parsed?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
process_name if group_parsed == :true and !last_line?
|
83
|
+
end
|
84
|
+
|
85
|
+
@groups
|
86
|
+
end
|
87
|
+
|
88
|
+
def extract_resources(args)
|
89
|
+
resources = args.first
|
90
|
+
|
91
|
+
case resources
|
92
|
+
when String
|
93
|
+
[resources]
|
94
|
+
when Array
|
95
|
+
resources
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def extract_groups_name(arguments)
|
102
|
+
extract_resources(arguments).join(" ")
|
103
|
+
end
|
104
|
+
|
105
|
+
def log_number_of_groups(raw_output)
|
106
|
+
@number_of_groups = raw_output.scan(GROUP_CLUE).size
|
107
|
+
Racf.logger.info("Processing #{@number_of_groups} group(s)")
|
108
|
+
end
|
109
|
+
|
110
|
+
def process_name
|
111
|
+
Racf.logger.info("Processing group #{@group_index} of #{@number_of_groups} groups")
|
112
|
+
|
113
|
+
if match_data = @current_line.match(/INFORMATION FOR GROUP (.*?)$/)
|
114
|
+
group_name = match_data[1]
|
115
|
+
Racf.logger.info("\tGroup name: #{group_name}")
|
116
|
+
@groups[group_name.to_sym] = @current_group
|
117
|
+
super
|
118
|
+
else
|
119
|
+
register_not_found_group
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def register_not_found_group
|
124
|
+
Racf.logger.info("\tGroup not found")
|
125
|
+
@group_index += 1
|
126
|
+
end
|
127
|
+
|
128
|
+
def process_superior_group_and_owner
|
129
|
+
match_data = @current_line.match(/SUPERIOR GROUP=(.*?)\s+OWNER=(.*)$/)
|
130
|
+
@current_group[:superior_group] = match_data[1]
|
131
|
+
@current_group[:owner] = match_data[2]
|
132
|
+
|
133
|
+
super
|
134
|
+
end
|
135
|
+
|
136
|
+
def process_description
|
137
|
+
if match_data = @current_line.match(/INSTALLATION DATA=(.*?)$/)
|
138
|
+
@current_group[:description] = match_data[1]
|
139
|
+
elsif @current_line == "NO INSTALLATION DATA"
|
140
|
+
@current_group[:description] = "NO DESCRIPTION"
|
141
|
+
else
|
142
|
+
raise
|
143
|
+
end
|
144
|
+
|
145
|
+
super
|
146
|
+
end
|
147
|
+
|
148
|
+
def process_subgroups
|
149
|
+
if @current_line.match(/NO SUBGROUPS/)
|
150
|
+
@current_group[:subgroups] = []
|
151
|
+
super
|
152
|
+
elsif match_data = @current_line.match(/SUBGROUP\(S\)=(.*?)$/)
|
153
|
+
subgroups = match_data[1].strip
|
154
|
+
@current_group[:subgroups] = subgroups.split(" ")
|
155
|
+
super
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def process_members
|
160
|
+
@members_parser.parse(@current_line)
|
161
|
+
@current_group[:members].merge!(@members_parser.members) if @members_parser.parsed?
|
162
|
+
end
|
163
|
+
|
164
|
+
def next_group?
|
165
|
+
@current_line.match(GROUP_CLUE)
|
166
|
+
end
|
167
|
+
|
168
|
+
def members_parsed?
|
169
|
+
@members_parser.parsed? && (next_group? || last_line?)
|
170
|
+
end
|
171
|
+
|
172
|
+
def last_line?
|
173
|
+
@line_number == @number_of_lines
|
174
|
+
end
|
175
|
+
|
176
|
+
def finish_group_parsing
|
177
|
+
@current_group[:members].merge!(@members_parser.members)
|
178
|
+
|
179
|
+
@members_parser = nil
|
180
|
+
@current_group = {}
|
181
|
+
@group_index += 1
|
182
|
+
|
183
|
+
super
|
184
|
+
|
185
|
+
throw(:group_parsed, :true)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|