sql_cmd 0.3.0 → 0.3.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 266298d96407b2fb372453d3989ef5fb21047f1a364c857c3c559e1826257d5a
4
- data.tar.gz: b3053a685e3e0202e1b68bddb20cec62bce549f6d7a8f7164ead4709f355dd9a
3
+ metadata.gz: 4df6d540e8235db2ebe06497947f8be105e7232f040d988378f75996be6624c2
4
+ data.tar.gz: c2b4f51d378cd9b7372aca4b364270756d3a55640d85110e9999c5f79c52e243
5
5
  SHA512:
6
- metadata.gz: 99aab9a7af85a77a7da945aaff55823364b497ef4d91d2551994362d87120c379784b8ff753d4339ac44ca91d14ba1c02f17f07942c03646f956c5c9da609190
7
- data.tar.gz: 5c6b0287eb928e2356e99b329eee771f5add55af0b13d0ec29e131fee1ab1590c7c726dcfd280d25b96e753b5febc8626841c844e4ae1f122468b8270d19e923
6
+ metadata.gz: fa6c6886afc7595a4cdacd0fceeb1dc10aa5ad2edc0f440bcabe634ec1d35978acaee61eae509db8bfe56418d867bfed95a32a1f318362dd3377d6d3b9a5edba
7
+ data.tar.gz: b233b667fe7e1942efb56bd8a0cf20162f46405f1ff5ab3bd41ddcf768e67064aa57b3934d8aa0fcc197188bc886ab6b596adb61498637da6c9cf4ad10fa2bb5
@@ -263,5 +263,10 @@ module SqlCmd
263
263
  raise 'Failed to remove database from AlwaysOn Availability Group' unless database_info['AvailabilityGroup'].nil? && replica_database_info['AvailabilityGroup'].nil?
264
264
  EasyIO.logger.info "[#{database_name}] removed from AlwaysOn availability group successfully..."
265
265
  end
266
+
267
+ def enabled?(connection_string)
268
+ server_info = SqlCmd.get_sql_server_settings(connection_string)
269
+ server_info['AvailabilityGroup'].nil? || server_info['SecondaryReplica'].nil?
270
+ end
266
271
  end
267
272
  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.
@@ -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)
@@ -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
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.1
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-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: easy_json_config