racf 0.6.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.
Files changed (63) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +18 -0
  4. data/Gemfile +14 -0
  5. data/Gemfile.lock +40 -0
  6. data/README.rdoc +56 -0
  7. data/Rakefile +9 -0
  8. data/TODO.txt +5 -0
  9. data/config/racf.yml.sample +27 -0
  10. data/lib/racf.rb +78 -0
  11. data/lib/racf/client.rb +138 -0
  12. data/lib/racf/commands/abstract_command.rb +13 -0
  13. data/lib/racf/commands/listgrp.rb +189 -0
  14. data/lib/racf/commands/listgrp/group_members_parser.rb +104 -0
  15. data/lib/racf/commands/listuser.rb +112 -0
  16. data/lib/racf/commands/rlist.rb +208 -0
  17. data/lib/racf/commands/search.rb +31 -0
  18. data/lib/racf/pagers/cached_ispf_pager.rb +91 -0
  19. data/lib/racf/pagers/ispf_pager.rb +57 -0
  20. data/lib/racf/s3270.rb +136 -0
  21. data/lib/racf/session.rb +149 -0
  22. data/lib/racf/version.rb +3 -0
  23. data/racf.gemspec +16 -0
  24. data/script/ci +3 -0
  25. data/spec/fixtures/config/racf.yml +9 -0
  26. data/spec/fixtures/listgrp/multiple_groups_multiple_members.txt +26 -0
  27. data/spec/fixtures/listgrp/multiple_members.txt +10 -0
  28. data/spec/fixtures/listgrp/no_members.txt +4 -0
  29. data/spec/fixtures/listgrp/not_found_groups.txt +21 -0
  30. data/spec/fixtures/listgrp/one_group.txt +7 -0
  31. data/spec/fixtures/listgrp/one_group_with_members.txt +13 -0
  32. data/spec/fixtures/listgrp/one_member.txt +7 -0
  33. data/spec/fixtures/listuser/all_users.txt +45 -0
  34. data/spec/fixtures/listuser/just_users_not_found.txt +3 -0
  35. data/spec/fixtures/listuser/one_user.txt +47 -0
  36. data/spec/fixtures/listuser/some_not_found_users.txt +88 -0
  37. data/spec/fixtures/racf_cache_dump.yml +9 -0
  38. data/spec/fixtures/rlist/gims.txt +135 -0
  39. data/spec/fixtures/rlist/gims_with_no_tims.txt +135 -0
  40. data/spec/fixtures/rlist/gims_with_not_found.txt +89 -0
  41. data/spec/fixtures/rlist/just_one_not_found.txt +1 -0
  42. data/spec/fixtures/rlist/multiple_not_found.txt +3 -0
  43. data/spec/fixtures/rlist/rlist_success.txt +50 -0
  44. data/spec/fixtures/rlist/tims_without_users.txt +119 -0
  45. data/spec/fixtures/search/gims.txt +30 -0
  46. data/spec/fixtures/search/tims.txt +30 -0
  47. data/spec/fixtures/session/screen_with_bottom_menu.txt +31 -0
  48. data/spec/fixtures/session/screen_with_top_and_bottom_menu.txt +47 -0
  49. data/spec/fixtures/session/screen_with_top_menu.txt +29 -0
  50. data/spec/fixtures/session/screen_without_menu.txt +13 -0
  51. data/spec/racf/client_spec.rb +155 -0
  52. data/spec/racf/commands/listgrp/group_members_parser_spec.rb +82 -0
  53. data/spec/racf/commands/listgrp_spec.rb +303 -0
  54. data/spec/racf/commands/listuser_spec.rb +123 -0
  55. data/spec/racf/commands/rlist_spec.rb +257 -0
  56. data/spec/racf/commands/search_spec.rb +66 -0
  57. data/spec/racf/pagers/cached_ispf_pager_spec.rb +212 -0
  58. data/spec/racf/pagers/ispf_pager_spec.rb +59 -0
  59. data/spec/racf/session_spec.rb +114 -0
  60. data/spec/racf_spec.rb +106 -0
  61. data/spec/spec_helper.rb +18 -0
  62. data/spec/support/helpers.rb +5 -0
  63. metadata +162 -0
@@ -0,0 +1,8 @@
1
+ .bundle
2
+ b/*
3
+ *.gem
4
+ .rvmrc
5
+ tmp/*
6
+ log/*
7
+ examples*
8
+ config/racf.yml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
@@ -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
@@ -0,0 +1,14 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in racf.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem "rake"
8
+ end
9
+
10
+ group :test do
11
+ gem "rspec"
12
+ gem "ruby-debug", :platform => :ruby_18
13
+ gem "awesome_print"
14
+ end
@@ -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
@@ -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
+
@@ -0,0 +1,9 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "bundler/gem_tasks"
5
+ require "rspec/core/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task :default => :spec
@@ -0,0 +1,5 @@
1
+ TODO
2
+
3
+ * add raw API to dump Racf data, instead of parsed one
4
+ * improve close connection reliability
5
+
@@ -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
+
@@ -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
@@ -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,13 @@
1
+ module Racf
2
+ module Commands
3
+ class AbstractCommand
4
+ def initialize(session)
5
+ @session = session
6
+ end
7
+
8
+ def extract_resources(*args)
9
+ raise NotImplementedError.new("Subclass must implement method extract_resources.")
10
+ end
11
+ end
12
+ end
13
+ 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