ass_maintainer-info_base 0.1.2 → 1.0.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.
@@ -1,16 +1,18 @@
1
1
  module AssMaintainer
2
2
  class InfoBase
3
- # @abstract
4
- class AbstractCfg
5
- attr_reader :infobase
6
- # @param infobase [InfoBase]
7
- def initialize(infobase)
8
- @infobase = infobase
3
+ module Abstract
4
+ # @abstract
5
+ class Cfg
6
+ attr_reader :infobase
7
+ # @param infobase [InfoBase]
8
+ def initialize(infobase)
9
+ @infobase = infobase
10
+ end
9
11
  end
10
12
  end
11
13
 
12
14
  # Object for manipuate whith infobase configuration
13
- class Cfg < AbstractCfg
15
+ class Cfg < Abstract::Cfg
14
16
  # Dump configuration to +XML+ files
15
17
  # @param path [String]
16
18
  # @return [String] path
@@ -55,14 +57,16 @@ module AssMaintainer
55
57
  end
56
58
 
57
59
  # Object for manipuate whith database configuration
58
- class DbCfg < AbstractCfg
60
+ class DbCfg < Abstract::Cfg
59
61
  # Update database configuration from infobase
60
62
  # configuration
61
- def update
63
+ # @param was_err [true false] control +warningsAsErrors+ 1C:Enterprise
64
+ # CLI parameter
65
+ def update(was_err = false)
62
66
  fail MethodDenied, :update if infobase.read_only?
63
67
  infobase.designer do
64
68
  updateDBCfg do
65
- warningsAsErrors
69
+ warningsAsErrors if was_err
66
70
  end
67
71
  end.run.wait.result.verify!
68
72
  end
File without changes
File without changes
@@ -10,11 +10,6 @@ module AssMaintainer
10
10
  end
11
11
  end
12
12
 
13
- # True if infobase exists
14
- def exists?
15
- File.file?("#{connection_string.path}/1Cv8.1CD")
16
- end
17
-
18
13
  def maker
19
14
  options[:maker] || InfoBase::DefaultMaker.new
20
15
  end
@@ -25,51 +20,39 @@ module AssMaintainer
25
20
  end
26
21
  private :destroyer
27
22
 
28
- # Connection string fore createinfobase
29
- def make_connection_string
30
- connection_string
23
+ # (see Interfaces::InfoBase#sessions)
24
+ def sessions
25
+ []
31
26
  end
32
27
 
33
- # Dummy infobase wrupper
34
- # @return [InfoBaseWrapper]
35
- def infobase_wrapper
36
- @infobase_wrapper = InfoBaseWrapper.new(self)
28
+ # (see Interfaces::InfoBase#lock)
29
+ def lock(*_)
37
30
  end
38
31
 
39
- # (see Interfaces::InfoBaseWrapper)
40
- class InfoBaseWrapper
41
- include Interfaces::InfoBaseWrapper
42
- attr_accessor :infobase
43
- def initialize(infobase)
44
- self.infobase = infobase
45
- end
46
-
47
- # (see Interfaces::InfoBaseWrapper#sessions)
48
- def sessions
49
- []
50
- end
32
+ # (see Interfaces::InfoBase#unlock)
33
+ def unlock
34
+ end
51
35
 
52
- # (see Interfaces::InfoBaseWrapper#lock)
53
- def lock
54
- end
36
+ # (see Interfaces::InfoBase#unlock!)
37
+ def unlock!
38
+ end
55
39
 
56
- # (see Interfaces::InfoBaseWrapper#unlock)
57
- def unlock
58
- end
40
+ # (see Interfaces::InfoBase#locked?)
41
+ def locked?
42
+ false
43
+ end
59
44
 
60
- # (see Interfaces::InfoBaseWrapper#unlock!)
61
- def unlock!
62
- end
45
+ # (see Interfaces::InfoBase#exists?)
46
+ def exists?
47
+ File.file?("#{connection_string.path}/1Cv8.1CD")
48
+ end
63
49
 
64
- # (see Interfaces::InfoBaseWrapper#locked?)
65
- def locked?
66
- false
67
- end
50
+ # (see Interfaces::InfoBase#lock_schjobs)
51
+ def lock_schjobs
52
+ end
68
53
 
69
- # (see Interfaces::InfoBaseWrapper#locked_we?)
70
- def locked_we?
71
- false
72
- end
54
+ # (see Interfaces::InfoBase#unlock_schjobs)
55
+ def unlock_schjobs
73
56
  end
74
57
  end
75
58
  end
@@ -1,5 +1,12 @@
1
1
  module AssMaintainer
2
2
  class InfoBase
3
+ # Riseses when infobase already locked and +InfoBase#unlock_code+
4
+ # does not macth +PermissionCode+ on server
5
+ class UnlockError < StandardError; end
6
+
7
+ # Raises when +InfoBase#unlock_code+ not setted
8
+ class LockError < StandardError; end
9
+
3
10
  # Define absract Interfaces
4
11
  # for worker classes
5
12
  module Interfaces
@@ -31,45 +38,67 @@ module AssMaintainer
31
38
  end
32
39
  end
33
40
 
34
- # Interface for {FileIb::InfoBaseWrapper} and
35
- # {ServerIb::InfoBaseWrapper} classes
36
- module InfoBaseWrapper
37
- # Returns array of infobase sessions
38
- # For file infobase returns empty array
39
- # @return [Array <Session>]
41
+ # Common interface for different infobase types
42
+ # Interface must be implemented in {InfoBase::FileIb} and
43
+ # {InfoBase::ServerIb} modules
44
+ module InfoBase
45
+ require 'date'
46
+
47
+ # @note For {InfoBase::FileIb} must returns empty array
48
+ # Returns array of infobase sessions exclude
49
+ # {InfoBase::Session::EXCLUDE_APP_IDS} application types
50
+ # @return [Array <InfoBase::Session>]
40
51
  def sessions
41
52
  fail NotImplementedError
42
53
  end
43
54
 
44
- # Lock infobase. It work for server infobase only.
45
- # For file infobase it do nothing
46
- def lock
55
+ # @note It must work for {InfoBase::ServerIb} only.
56
+ # For {InfoBase::FileIb} it must do nothing
57
+ # Locking infobase if it possible. Be careful it terminate all
58
+ # sessions! Before do it should set +InfoBase#unlock_code+!
59
+ # Schedule jobs will be locked to!
60
+ # @raise [LockError] unless +InfoBase#unlock_code+ setted
61
+ # @raise [UnlockError] unless soft {#unlock} possible. If catched
62
+ # it, shold do force unlock {unlock!} and try againe
63
+ def lock(from: Time.now, to: Time.now + 3600, message: '')
47
64
  fail NotImplementedError
48
65
  end
49
66
 
50
- # Unlock infobase which {#locked_we?}.
51
- # It work for server infobase only.
52
- # For file infobase it do nothing
67
+ # @note (see #lock)
68
+ # Soft unlocking infobase if it possible.
69
+ # For force unlocking exec #{unlock!}
70
+ # @raise [UnlockError] unless unlocking possible
53
71
  def unlock
54
72
  fail NotImplementedError
55
73
  end
56
74
 
57
- # Unlock infobase.
58
- # It work for server infobase only.
59
- # For file infobase it do nothing
75
+ # @note (see #lock)
76
+ # Force unlock infobase.
60
77
  def unlock!
61
78
  fail NotImplementedError
62
79
  end
63
80
 
64
- # Lock infobase. It work for server infobase only.
65
- # For file infobase it return +false+
81
+ # @note (see #lock)
82
+ # Lock schedule jobs
83
+ def lock_schjobs
84
+ fail NotImplementedError
85
+ end
86
+
87
+ # @note (see #lock)
88
+ # Unlock schedule jobs
89
+ def unlock_schjobs
90
+ fail NotImplementedError
91
+ end
92
+
93
+ # @note For {InfoBase::FileIb} it must always return +false+
94
+ # It work for {InfoBase::ServerIb} only.
95
+ # Return +true+ if on server flag +SessionsDenied == true+
66
96
  def locked?
67
97
  fail NotImplementedError
68
98
  end
69
99
 
70
- # True if infobase locked this
71
- # For file infobase it return +false+
72
- def locked_we?
100
+ # True if infobase exists
101
+ def exists?
73
102
  fail NotImplementedError
74
103
  end
75
104
  end
@@ -1,97 +1,299 @@
1
1
  module AssMaintainer
2
2
  class InfoBase
3
+ class Session
4
+ # AppID excluded from {Interfaces::InfoBase#sessions} array
5
+ # - SrvrConsole - cluster console
6
+ # - COMConsole - ole cluster console
7
+ # - OpenIDProvider - OpenID provider
8
+ # - RAS - administration server
9
+ EXCLUDE_APP_IDS = %w{SrvrConsole COMConsole OpenIDProvider RAS}
10
+
11
+ # see {#initialize} +app_id+
12
+ attr_reader :app_id
13
+
14
+ # see {#initialize} +host+
15
+ attr_reader :host
16
+
17
+ # see {#initialize} +id+
18
+ attr_reader :id
19
+
20
+ # see {#initialize} +user+
21
+ attr_reader :user
22
+
23
+ # see {#initialize} +infobase+
24
+ attr_reader :infobase
25
+
26
+ # @api private
27
+ # @param id [Fixnum] sessions id
28
+ # @param app_id [String] client application id
29
+ # @param host [String] client host name
30
+ # @param user [Strin] infobase user
31
+ # @param infobase [InfoBase] infobase instance
32
+ def initialize(id, app_id, host, user, infobase)
33
+ @id = id
34
+ @app_id = app_id
35
+ @host = host
36
+ @user = user
37
+ @infobase = infobase
38
+ end
39
+
40
+ # Terminate session
41
+ def terminate
42
+ infobase.send(:infobase_wrapper).terminate(self) unless terminated?
43
+ end
44
+
45
+ # True if session is terminated
46
+ def terminated?
47
+ infobase.send(:infobase_wrapper).session_get(id).empty?
48
+ end
49
+ end
50
+
3
51
  # Mixins for infobase deployed on 1C:Eneterprise server
4
52
  module ServerIb
5
- require 'ass_maintainer/info_base/server_ib/helpers'
6
- # Defauld destroyer for serever infobase
53
+ require 'ass_maintainer/info_base/server_ib/enterprise_servers'
54
+
55
+ # @api private
56
+ # Defauld destroyer for server infobase
7
57
  class ServerBaseDestroyer
58
+
59
+ # On default database will be destroyed!
60
+ DROP_MODE = :destroy_db
61
+
8
62
  include Interfaces::IbDestroyer
63
+
64
+ # {InfoBase::Interfaces::IbDestroyer#entry_point} overload
9
65
  def entry_point
10
- fail NotImplementedError
66
+ infobase.send(:infobase_wrapper).drop_infobase!(DROP_MODE)
11
67
  end
12
68
  end
13
69
 
14
- def maker
15
- options[:maker] || InfoBase::DefaultMaker.new
70
+ # @api private
71
+ # server infobase maker
72
+ class ServerBaseMaker < InfoBase::DefaultMaker
73
+
74
+ # Fields of {#connection_string} required for 1C command
75
+ # +createinfobase+
76
+ REQUIRE_FIELDS = [:dbsrvr, :dbuid, :dbms]
77
+
78
+ # {InfoBase::Interfaces::IbMaker#entry_point} overload
79
+ def entry_point
80
+ prepare_making
81
+ super
82
+ end
83
+
84
+ # Prepare {#connection_string} before execute making command
85
+ def prepare_making
86
+ fail "Fields #{REQUIRE_FIELDS} must be filled" unless require_filled?
87
+ cs = connection_string
88
+ set_if_empty :db, cs.ref
89
+ set_if_empty :crsqldb, 'Y'
90
+ set_if_empty :susr, infobase.cluster_usr
91
+ set_if_empty :spwd, infobase.cluster_pwd
92
+ end
93
+
94
+ # True if all fields from {REQUIRE_FIELDS} setted
95
+ # in {#connection_string}
96
+ def require_filled?
97
+ REQUIRE_FIELDS.each do |f|
98
+ return false if infobase.connection_string.send(f).nil?
99
+ end
100
+ true
101
+ end
102
+
103
+ # set {#connection_string} field +prop+ to +value+ if filed
104
+ # +prop+ empty?
105
+ # @param prop [String Symbol] field name
106
+ # @param value
107
+ def set_if_empty(prop, value)
108
+ connection_string.send("#{prop}=", value) if\
109
+ connection_string.send(prop).to_s.empty?
110
+ end
111
+
112
+ # Return {InfoBase#connection_string} instance
113
+ def connection_string
114
+ infobase.connection_string
115
+ end
16
116
  end
17
- private :maker
18
117
 
19
- # True if infobase exists
20
- def exists?
21
- infobase_wrapper.exists?
118
+ def maker
119
+ options[:maker] || ServerBaseMaker.new
22
120
  end
121
+ private :maker
23
122
 
24
123
  def destroyer
25
124
  options[:destroyer] || ServerBaseDestroyer.new
26
125
  end
27
126
  private :destroyer
28
127
 
29
- # @return (see #def_server_agent)
30
- def server_agent
31
- @server_agent ||= def_server_agent
128
+ # @return {InfoBaseWrapper}
129
+ def infobase_wrapper
130
+ @infobase_wrapper ||= InfoBaseWrapper.new(self)
32
131
  end
132
+ private :infobase_wrapper
33
133
 
34
- # @return [EnterpriseServers::ServerAgent]
35
- def def_server_agent
36
- host = sagent_host || connection_string.servers[0].host
37
- port = sagent_port || InfoBase::DEFAULT_SAGENT_PORT
38
- EnterpriseServers::ServerAgent.new("#{host}:#{port}",
39
- sagent_usr,
40
- sagent_pwd)
134
+ def wp_connection
135
+ infobase_wrapper.wp_connection
41
136
  end
42
- private :def_server_agent
137
+ private :wp_connection
43
138
 
44
- # @param a [EnterpriseServers::ServerAgent]
45
- def server_agent=(a)
46
- fail ArgumentError unless a.instance_of? ServerAgent
47
- @server_agent = a
139
+ # (see Interfaces::InfoBase#sessions)
140
+ def sessions
141
+ infobase_wrapper.sessions.map do |s|
142
+ s.to_session(self) unless Session::EXCLUDE_APP_IDS.include? s.AppId
143
+ end.compact
48
144
  end
49
145
 
50
- # Set claster user name
51
- # @param user_name [String]
52
- def cluster_usr=(user_name)
53
- connection_string.susr = user_name
146
+ # (see Interfaces::InfoBase#lock)
147
+ def lock(from: Time.now, to: Time.now + 3600, message: '')
148
+ fail LockError, '#unlock_code is required' if unlock_code.to_s.empty?
149
+ unlock
150
+ wp_connection.lock_sessions!(from, to, unlock_code, message)
151
+ lock_schjobs
152
+ sessions.each do |sess|
153
+ sess.terminate
154
+ end
155
+ nil
54
156
  end
55
157
 
56
- # Claster user name
57
- def claster_usr
58
- connection_string.susr || (self.claster_usr = options[:claster_usr])
158
+ # (see Interfaces::InfoBase#unlock)
159
+ def unlock
160
+ wp_connection.raise_unless_unlock_possable UnlockError, unlock_code
161
+ unlock!
162
+ nil
59
163
  end
60
164
 
61
- # Set claster user password
62
- # @param password [String]
63
- def cluster_pwd=(password)
64
- connection_string.spwd = password
165
+ # (see Interfaces::InfoBase#unlock!)
166
+ def unlock!
167
+ wp_connection.unlock_schjobs!
168
+ wp_connection.unlock_sessions!
169
+ nil
65
170
  end
66
171
 
67
- # Claster user password
68
- def claster_pwd
69
- connection_string.spwd || (self.claster_pwd = options[:claster_pwd])
172
+ # (see Interfaces::InfoBase#lock_schjobs)
173
+ def lock_schjobs
174
+ wp_connection.lock_schjobs!
175
+ nil
70
176
  end
71
177
 
72
- # @return [EnrepriseServers::Claster]
73
- def claster
74
- EnterpriseServers::Claster.from_cs(connection_string)
178
+ # (see Interfaces::InfoBase#unlock_schjobs)
179
+ def unlock_schjobs
180
+ wp_connection.unlock_schjobs!
181
+ nil
75
182
  end
76
183
 
77
- def filled?(fields)
78
- fields.each do |f|
79
- return false if connection_string[f].nil?
80
- end
81
- true
184
+ # (see Interfaces::InfoBase#locked?)
185
+ def locked?
186
+ wp_connection.locked?
82
187
  end
83
- private :filled?
84
188
 
85
- # Connection string fore createinfobase
86
- def make_connection_string
87
- fields = [:dbsrvr, :db, :dbms]
88
- fail "Required fields #{fields} must be filled" unless filled?(fields)
89
- AssLauncher::Support::ConnectionString.new(connection_string.to_s)
189
+ # (see Interfaces::InfoBase#exists?)
190
+ def exists?
191
+ infobase_wrapper.exists?
90
192
  end
91
193
 
92
- # @return {InfoBaseWrapper}
93
- def infobase_wrapper
94
- @infobase_wrapper = InfoBaseWrapper.new(self, server_agent, claster)
194
+ # @api private
195
+ # Wrapper for manipulate
196
+ # with real information base deployed in 1C:Enterprise server
197
+ # ower the 1C Ole classes
198
+ class InfoBaseWrapper
199
+ attr_accessor :infobase
200
+ alias_method :ib, :infobase
201
+ def initialize(infobase)
202
+ self.infobase = infobase
203
+ end
204
+
205
+ # @return [EnterpriseServers::ServerAgent]
206
+ def sagent_get
207
+ EnterpriseServers::ServerAgent
208
+ .new "#{ib.sagent_host || cs_servers[0].host}:#{ib.sagent_port}",
209
+ ib.sagent_usr,
210
+ ib.sagent_pwd
211
+ end
212
+ private :sagent_get
213
+
214
+ def exists?
215
+ clusters.size > 0
216
+ end
217
+
218
+ # @return [AssLauncher::Enterprise::Ole::AgentConnection]
219
+ def sagent
220
+ @sagent ||= sagent_get.connect(infobase.platform_require)
221
+ end
222
+
223
+ def cs_servers
224
+ ib.connection_string.servers.uniq {|s| [s.host.upcase, s.port.upcase]}
225
+ end
226
+ private :cs_servers
227
+
228
+ def cs_clusters
229
+ cs_servers.map do |s|
230
+ EnterpriseServers::Cluster
231
+ .new("#{s.host}:#{s.port}", ib.cluster_usr, ib.cluster_pwd)
232
+ end
233
+ end
234
+ private :cs_clusters
235
+
236
+ def fail_multiple_servers_not_support
237
+ fail NotImplementedError,
238
+ 'Multiple clusters deployment not supported' if\
239
+ cs_servers.size > 1
240
+ end
241
+ private :fail_multiple_servers_not_support
242
+
243
+ # @return [Array<EnterpriseServers::Cluster>] clusters defined in
244
+ # +#infobase.clusters+ attached into {#sagent}
245
+ # @raise [RuntimeError] unsupport multiple servers infobase deployments
246
+ def clusters
247
+ fail_multiple_servers_not_support
248
+ cs_clusters.select do |cl|
249
+ cl.attach(sagent).infobase_include? ib_ref
250
+ end
251
+ end
252
+
253
+ def wp_connection
254
+ fail 'Infobase not exists' unless exists?
255
+ clusters[0].wp_connection(self)
256
+ end
257
+
258
+ # Helper
259
+ def ib_ref
260
+ ib.connection_string.ref
261
+ end
262
+
263
+ # @param session [InfoBase::Session]
264
+ def terminate(session)
265
+ session_get(session.id).each do |s|
266
+ s.terminate
267
+ end
268
+ end
269
+
270
+ # Helper select session per +ID+. In normal returns arry with single
271
+ # element or empty array
272
+ # @return [Array<EnterpriseServers::Wrappers::Session>]
273
+ def session_get(id)
274
+ sessions.select {|s| s.SessionId().to_s == id.to_s}
275
+ end
276
+
277
+ # @return [Array<EnterpriseServers::Wrappers::Session>] infobase
278
+ # sessions
279
+ def sessions
280
+ return [] unless exists?
281
+ clusters.map do |cl|
282
+ cl.infobase_sessions(ib_ref)
283
+ end.flatten
284
+ end
285
+
286
+ # Dlete infobase.
287
+ # @note For first item calls {EnterpriseServers::Cluster#drop_infobase!}
288
+ # with real +mode+ and uses mode == :alive_db for all other.
289
+ # Otherwise when mode == :destroy_db raises error
290
+ # "Не найдена база данных * в SQL-сервере *"
291
+ # @param mode (see Cluster#drop_infobase!)
292
+ def drop_infobase!(mode)
293
+ clusters.each_with_index do |cl, index|
294
+ cl.drop_infobase!(self, (index == 0 ? mode : :alive_db))
295
+ end
296
+ end
95
297
  end
96
298
  end
97
299
  end