racf 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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