sql_cmd 0.3.0 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 266298d96407b2fb372453d3989ef5fb21047f1a364c857c3c559e1826257d5a
4
- data.tar.gz: b3053a685e3e0202e1b68bddb20cec62bce549f6d7a8f7164ead4709f355dd9a
3
+ metadata.gz: 84ae28535256cbad4ab450ea06fe4807b593b938548edc13f3edad224174f819
4
+ data.tar.gz: d6dfe44866a53bbc52d4bc7ebd1caf80d521a8b8ce70a56d7af9dc5bae3bc5cd
5
5
  SHA512:
6
- metadata.gz: 99aab9a7af85a77a7da945aaff55823364b497ef4d91d2551994362d87120c379784b8ff753d4339ac44ca91d14ba1c02f17f07942c03646f956c5c9da609190
7
- data.tar.gz: 5c6b0287eb928e2356e99b329eee771f5add55af0b13d0ec29e131fee1ab1590c7c726dcfd280d25b96e753b5febc8626841c844e4ae1f122468b8270d19e923
6
+ metadata.gz: d89c55abf7b3cf3abc9bc03d4ee15077326054b959af3a22f68e3b0278cd3af23a12dd027521cfc50d036cc888b5d0b515c62089424079bef7c535a9a55bdd82
7
+ data.tar.gz: dc56ef0c9e56263982497ef965a9108ab0710a10992dcad49a9f67e81bd4f451eeaa41f64e182e0a1ff2d628ef061844e66e0c745842c99225d699ff25193b52
@@ -62,8 +62,10 @@ module SqlCmd
62
62
  EasyIO.logger.header 'AlwaysOn Permissions Migration to Replica'
63
63
  EasyIO.logger.debug 'Migrating logins to replica...'
64
64
  import_script_filename = SqlCmd.export_logins(start_time, primary_connection_string, database_name)
65
- EasyIO.logger.info "Importing logins on [#{SqlCmd.connection_string_part(replica_connection_string, :server)}]..."
66
- SqlCmd.execute_script_file(replica_connection_string, import_script_filename)
65
+ unless import_script_filename.nil?
66
+ EasyIO.logger.info "Importing logins on [#{SqlCmd.connection_string_part(replica_connection_string, :server)}]..."
67
+ SqlCmd.execute_script_file(replica_connection_string, import_script_filename)
68
+ end
67
69
  EasyIO.logger.debug 'Running database_status script...'
68
70
  database_info = SqlCmd::Database.info(connection_string, database_name)
69
71
  replica_database_info = SqlCmd::Database.info(replica_connection_string, database_name)
@@ -263,5 +265,10 @@ module SqlCmd
263
265
  raise 'Failed to remove database from AlwaysOn Availability Group' unless database_info['AvailabilityGroup'].nil? && replica_database_info['AvailabilityGroup'].nil?
264
266
  EasyIO.logger.info "[#{database_name}] removed from AlwaysOn availability group successfully..."
265
267
  end
268
+
269
+ def enabled?(connection_string)
270
+ server_info = SqlCmd.get_sql_server_settings(connection_string)
271
+ !server_info['AvailabilityGroup'].nil? && !server_info['SecondaryReplica'].nil?
272
+ end
266
273
  end
267
274
  end
@@ -54,22 +54,27 @@ module SqlCmd
54
54
  files.map { |f, properties| ["#{base_url}/#{f}", properties[:last_modified]] }.to_h
55
55
  end
56
56
 
57
- def backup_location_and_basename(start_time, connection_string, database_name, options = {}, backup_url: nil)
57
+ def backup_location_and_basename(start_time, connection_string, database_name, options = {}, backup_folder: nil, backup_url: nil, backup_basename: nil)
58
58
  start_time = SqlCmd.unify_start_time(start_time)
59
59
  database_info = SqlCmd::Database.info(connection_string, database_name)
60
60
  server_settings = get_sql_server_settings(connection_string)
61
61
  backup_type = backup_url.nil? || backup_url.empty? ? 'DISK' : 'URL'
62
62
  if database_info['DatabaseNotFound']
63
- backup_name = "#{database_name}_#{EasyTime.yyyymmdd(start_time)}"
64
- return [backup_url, backup_name] if backup_type == 'URL'
63
+ backup_basename = "#{database_name}_#{EasyTime.yyyymmdd(start_time)}"
64
+ return [backup_url, backup_basename] if backup_type == 'URL'
65
65
  backup_unc_location = SqlCmd.config['sql_cmd']['backups']['backup_to_host_sql_server'] ? "\\\\#{server_settings['ServerName']}\\#{SqlCmd.config['sql_cmd']['backups']['default_backup_share']}" : SqlCmd.config['sql_cmd']['backups']['default_destination']
66
- return Dir.glob("#{backup_unc_location}/#{backup_name}*".tr('\\', '/')).empty? ? [nil, nil] : [backup_unc_location, backup_name]
66
+ return Dir.glob("#{backup_unc_location}/#{backup_basename}*".tr('\\', '/')).empty? ? [nil, nil] : [backup_unc_location, backup_basename]
67
67
  end
68
68
 
69
69
  backup_file_path = database_info['BackupFileLocation']
70
+ if backup_file_path =~ /^\{.*\}$/
71
+ backup_basename ||= "#{database_name}_#{EasyTime.yyyymmdd(start_time)}"
72
+ backup_files, backup_basename = SqlCmd::Database.existing_backup_files(server_settings, options, backup_folder: backup_folder, backup_url: backup_url, backup_basename: backup_basename, log_only: options['logonly'])
73
+ backup_file_path = backup_files.first
74
+ end
70
75
  backup_file = ::File.basename(backup_file_path)
71
- backup_name = backup_basename(backup_file)
72
- return [nil, backup_name] if backup_type == 'URL'
76
+ backup_basename = backup_basename_from_path(backup_file)
77
+ return [nil, backup_basename] if backup_type == 'URL'
73
78
  backup_unc_location = to_unc_path(::File.dirname(backup_file_path), server_settings['ServerName'])
74
79
  backup_folder = if ::File.exist?("#{backup_unc_location}/#{backup_file}")
75
80
  backup_unc_location
@@ -77,7 +82,7 @@ module SqlCmd
77
82
  "\\\\#{server_settings['ServerName']}\\#{SqlCmd.config['sql_cmd']['backups']['default_backup_share']}"
78
83
  end
79
84
  return [nil, nil] unless defined?(backup_folder)
80
- [backup_folder, backup_name]
85
+ [backup_folder, backup_basename]
81
86
  end
82
87
 
83
88
  # sql_server_settings can be for any server that has network access to these files
@@ -313,10 +313,10 @@ module SqlCmd
313
313
  SqlCmd.run_sql_as_job(connection_string, sql_backup_script, "Backup: #{backup_basename}", values: values, retries: 1, retry_delay: 30)
314
314
  end
315
315
 
316
- def monitor_backup(backup_start_time, connection_string, database_name, options = {}, backup_folder: nil, backup_url: nil, backup_basename: nil, log_only: false, retries: 3, retry_delay: 10)
316
+ def monitor_backup(backup_start_time, connection_string, database_name, options = {}, job_name: nil, backup_folder: nil, backup_url: nil, backup_basename: nil, log_only: false, retries: 3, retry_delay: 10)
317
317
  backup_start_time = SqlCmd.unify_start_time(backup_start_time)
318
318
  backup_status_script = ::File.read("#{SqlCmd.sql_script_dir}/Status/BackupProgress.sql")
319
- job_name = "Backup: #{database_name}"
319
+ job_name ||= "Backup: #{database_name}"
320
320
  EasyIO.logger.info 'Checking backup status...'
321
321
  EasyIO.logger.debug "Backup start time: #{backup_start_time}"
322
322
  sleep(3) # Give the job time to start
@@ -340,9 +340,9 @@ module SqlCmd
340
340
  # job_message = job_history_message(connection_string, job_name) unless result == :current
341
341
  if job_started # Check if job has timed out after stopping without completing
342
342
  job_completion_time ||= Time.now
343
- _raise_backup_failure(connection_string, database_name, last_backup_date_key, backup_start_time, backup_basename, job_status: job_status, job_started: job_started) if Time.now > job_completion_time + timeout
343
+ _raise_backup_failure(connection_string, database_name, last_backup_date_key, backup_start_time, job_name, job_status: job_status, job_started: job_started) if Time.now > job_completion_time + timeout
344
344
  elsif Time.now > monitoring_start_time + timeout # Job never started and timed out
345
- _raise_backup_failure(connection_string, database_name, last_backup_date_key, backup_start_time, backup_basename, job_status: job_status, job_started: job_started)
345
+ _raise_backup_failure(connection_string, database_name, last_backup_date_key, backup_start_time, job_name, job_status: job_status, job_started: job_started)
346
346
  end
347
347
  sleep(timer_interval)
348
348
  next
@@ -380,18 +380,18 @@ module SqlCmd
380
380
  result
381
381
  end
382
382
 
383
- def _raise_backup_failure(connection_string, database_name, last_backup_date_key, backup_start_time, backup_basename, job_status: nil, job_started: false)
383
+ def _raise_backup_failure(connection_string, database_name, last_backup_date_key, backup_start_time, job_name, job_status: nil, job_started: false)
384
384
  server_name = SqlCmd.connection_string_part(connection_string, :server)
385
- if job_started
386
- failure_message = "Backup may have failed as the backup has stopped and the last backup time shows #{SqlCmd::Database.info(connection_string, database_name)[last_backup_date_key]} " \
387
- "but the backup should be newer than #{backup_start_time}! "
388
- failure_message += job_status == 'NoJob' ? 'The job exited with success and so does not exist!' : "Check sql job 'Backup: #{backup_basename}' history on [#{server_name}] for details. \n"
389
- raise failure_message + "Last backup time retrieved from: #{server_name}\\#{database_name}"
390
- end
391
- failure_message = "Backup appears to have failed! The last backup time shows #{SqlCmd::Database.info(connection_string, database_name)[last_backup_date_key]} " \
392
- "but the backup should be newer than #{backup_start_time}! "
393
- failure_message += job_status == 'NoJob' ? 'The backup job could not be found!' : "The job did not start in time. Check sql job 'Backup: #{backup_basename}' history on [#{server_name}] for details."
394
- raise failure_message + "Last backup time retrieved from: #{server_name}\\#{database_name}"
385
+ failure_message = if job_started
386
+ "Backup may have failed as the backup has stopped and the last backup time shows #{SqlCmd::Database.info(connection_string, database_name)[last_backup_date_key]} " \
387
+ "but the backup should be newer than #{backup_start_time}! " +
388
+ (job_status == 'NoJob' ? 'The job exited with success and so does not exist!' : "Check sql job '#{job_name}' history on [#{server_name}] for details. \n")
389
+ else
390
+ "Backup appears to have failed! The last backup time shows #{SqlCmd::Database.info(connection_string, database_name)[last_backup_date_key]} " \
391
+ "but the backup should be newer than #{backup_start_time}! " +
392
+ (job_status == 'NoJob' ? 'The backup job could not be found!' : "The job did not start in time. Check sql job '#{job_name}' history on [#{server_name}] for details.")
393
+ end
394
+ raise failure_message + " Last backup time retrieved from: #{server_name}\\#{database_name}"
395
395
  end
396
396
 
397
397
  # Creates and starts a SQL job to restore a database.
@@ -477,7 +477,7 @@ module SqlCmd
477
477
  end
478
478
  failure_message = 'Restore appears to have failed! '
479
479
  failure_message += job_status == 'NoJob' ? 'The job could not be found and the restored database is not up to date!' : "The job did not start in time. Check sql job 'Restore: #{database_name}' history on [#{server_name}] for details."
480
- raise failure_message + "Restore destination: #{server_name}\\#{database_name}"
480
+ raise failure_message + "\nRestore destination: #{server_name}\\#{database_name}"
481
481
  end
482
482
 
483
483
  def check_restore_date(start_time, connection_string, database_name, messages = :none, log_only: false)
@@ -500,8 +500,8 @@ module SqlCmd
500
500
  database_info = info(connection_string, database_name) if database_info.nil?
501
501
  server_name = SqlCmd.connection_string_part(connection_string, :server)
502
502
  EasyIO.logger.info "Ensuring full backup has taken place for [#{server_name}].[#{database_name}]..."
503
- if force_backup || database_info['LastNonCopyOnlyFullBackupDate'].nil? || # Ensure last full backup occurred AFTER the DB was last restored
504
- (!database_info['LastRestoreDate'].nil? && database_info['LastNonCopyOnlyFullBackupDate'] < database_info['LastRestoreDate'])
503
+ start_time = database_info['LastRestoreDate'] || database_info['create_date']
504
+ if force_backup || database_info['LastNonCopyOnlyFullBackupDate'].nil? || (database_info['LastNonCopyOnlyFullBackupDate'] < start_time) # Ensure last full backup occurred AFTER the DB was last restored/created
505
505
  EasyIO.logger.info 'Running full backup...'
506
506
  backup_basename = "full_backup-#{database_name}_#{EasyTime.yyyymmdd}" # If a full_backup_method was not provided, use this name for the database backup for clarity
507
507
  full_backup_method.nil? ? SqlCmd::Database.backup(Time.now, connection_string, database_name, backup_basename: backup_basename, options: { 'copyonly' => false }) : full_backup_method.call
@@ -511,7 +511,7 @@ module SqlCmd
511
511
  def duplicate(start_time, source_connection_string, source_database_name, destination_connection_string, destination_database_name, backup_folder: nil, backup_url: nil, backup_basename: nil, force_restore: false, full_backup_method: nil, options: {})
512
512
  start_time = SqlCmd.unify_start_time(start_time)
513
513
  backup(start_time, source_connection_string, source_database_name, backup_folder: backup_folder, backup_url: backup_url, backup_basename: backup_basename, options: options) unless info(source_connection_string, source_database_name)['DatabaseNotFound']
514
- backup_folder, backup_basename = SqlCmd.backup_location_and_basename(start_time, source_connection_string, source_database_name, options, backup_url: backup_url) # TODO: rework for URL
514
+ backup_folder, backup_basename = SqlCmd.backup_location_and_basename(start_time, source_connection_string, source_database_name, options, backup_folder: backup_folder, backup_url: backup_url, backup_basename: backup_basename) # TODO: rework for URL
515
515
  if (backup_folder.nil? && backup_url.nil?) || backup_basename.nil?
516
516
  source_server = SqlCmd.connection_string_part(source_connection_string, :server)
517
517
  destination_server = SqlCmd.connection_string_part(destination_connection_string, :server)
@@ -535,7 +535,11 @@ module SqlCmd
535
535
  end
536
536
 
537
537
  def apply_recovery_model(connection_string, database_name, options)
538
- return if recovery_model_set?(connection_string, database_name, options)
538
+ if recovery_model_set?(connection_string, database_name, options)
539
+ EasyIO.logger.info "Recovery model already set to '#{options['recovery_model']}'. No change needed."
540
+ return
541
+ end
542
+ EasyIO.logger.info "Setting recovery model to '#{options['recovery_model']}'..."
539
543
  options['recovery_model'] ||= 'FULL'
540
544
  options['rollback'] ||= 'ROLLBACK IMMEDIATE' # other options: ROLLBACK AFTER 30, NO_WAIT
541
545
  sql_script = "ALTER DATABASE [#{database_name}] SET RECOVERY #{options['recovery_model']} WITH #{options['rollback']}"
@@ -547,6 +551,7 @@ module SqlCmd
547
551
  #{'=' * 120}\n"
548
552
  EOS
549
553
  raise failure_message unless recovery_model_set?(connection_string, database_name, options)
554
+ EasyIO.logger.info "Recovery model updated to '#{options['recovery_model']}'."
550
555
  end
551
556
 
552
557
  def recovery_model_set?(connection_string, database_name, options)
@@ -85,7 +85,7 @@ module SqlCmd
85
85
  end
86
86
 
87
87
  # get the basename of the backup based on a full file_path such as the SQL value from [backupmediafamily].[physical_device_name]
88
- def backup_basename(backup_path)
88
+ def backup_basename_from_path(backup_path)
89
89
  return nil if backup_path.nil? || backup_path.empty?
90
90
  ::File.basename(backup_path).gsub(/(\.part\d+)?\.(bak|trn)/i, '')
91
91
  end
data/lib/sql_cmd/query.rb CHANGED
@@ -83,7 +83,18 @@ module SqlCmd
83
83
  raise
84
84
  end
85
85
  ensure
86
- ::File.delete "#{@scripts_cache_windows}\\sql_helper_#{start_time}.ps1" if defined?(start_time) && ::File.exist?("#{@scripts_cache_windows}\\sql_helper_#{start_time}.ps1")
86
+ retry_count = 0
87
+ retries = 3
88
+ retry_delay = 3
89
+ begin
90
+ ::File.delete "#{@scripts_cache_windows}\\sql_helper_#{start_time}.ps1" if defined?(start_time) && ::File.exist?("#{@scripts_cache_windows}\\sql_helper_#{start_time}.ps1")
91
+ rescue # Try to delete the file 3 times
92
+ if (retry_count += 1) <= retries
93
+ sleep(retry_delay)
94
+ retry
95
+ end
96
+ raise
97
+ end
87
98
  end
88
99
 
89
100
  def convert_powershell_tables_to_hash(json_string, return_type = :all_tables, at_timezone: 'UTC', string_to_time_by: '%Y-%m-%d %H:%M:%S %z') # options: :all_tables, :first_table, :first_row
@@ -234,6 +245,7 @@ module SqlCmd
234
245
  def migrate_logins(start_time, source_connection_string, destination_connection_string, database_name)
235
246
  start_time = SqlCmd.unify_start_time(start_time)
236
247
  import_script_filename = export_logins(start_time, source_connection_string, database_name)
248
+ return if import_script_filename.nil?
237
249
  if ::File.exist?(import_script_filename)
238
250
  EasyIO.logger.info "Importing logins on [#{connection_string_part(destination_connection_string, :server)}]..."
239
251
  execute_script_file(destination_connection_string, import_script_filename)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql_cmd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Munoz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-15 00:00:00.000000000 Z
11
+ date: 2022-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: easy_json_config