module QuiversTaskrunner
Constants
- VERSION
Public Instance Methods
configure_subscription(env=nil)
click to toggle source
# File lib/quiverstaskrunner/azuresetup.rb, line 131 def configure_subscription(env=nil) # 1. Load environment variables env = env || EnvHelper.get_env("env") pfx_path = EnvHelper.get_env("azure_management_certificate") subscription_id = EnvHelper.get_env("azure_subscription_id") # 2. Load secrets storage = SettingsHelper.get_settings(File.join(Dir.pwd, @@secrets[:storage]), env, @@get_settings_options) storage_details = storage["blob"] raise StandardError, "No details were found for blob storage for the #{env} environment" unless storage_details Azure.configure do |config| config.storage_account_name = storage_details["name"] config.storage_access_key = storage_details["key"] config.management_certificate = pfx_path config.subscription_id = subscription_id config.management_endpoint = "https://management.core.windows.net" end end
create_azure_files_restore_points(files_to_backup)
click to toggle source
# File lib/quiverstaskrunner/restorepoints.rb, line 7 def create_azure_files_restore_points(files_to_backup) # convert single file into an array files = files_to_backup.is_a?(Array) ? files_to_backup : (files_to_backup.nil? ? [] : [files_to_backup]) files.each do |f| f_ext = File.extname(f) f_backup_ext = ".backup#{f_ext}" f_backup = f.gsub(f_ext, f_backup_ext) # 1. Delete previous backup files if there are still present FileUtils.rm_f(f_backup) if FileTest.exists? f_backup # 2. Create backup files FileUtils.cp f, f_backup end end
delete_staging(cloud_service_name, env=nil)
click to toggle source
# File lib/quiverstaskrunner/azuresetup.rb, line 338 def delete_staging(cloud_service_name, env=nil) # 1. Load cloud service's details env = env || EnvHelper.get_env("env") cloud_services = SettingsHelper.get_settings(File.join(Dir.pwd, @@secrets[:cloud_services]), env, @@get_settings_options) cloud_service_details = cloud_services[cloud_service_name] raise StandardError, "No details were found for cloud service #{cloud_service_name}" unless cloud_service_details cloud_srv_name = cloud_service_details["name"] # 2. Check if there is a Staging deployment for that Cloud Service cloud_srv_mgmt = Azure::CloudServiceManagementService.new deployment = cloud_srv_mgmt.get_deployment(cloud_srv_name, {:slot => "staging", :no_exit_on_failure => true}) # 3. Delete the Staging deployment if it exists start_time = Time.now if deployment.exists? puts "Deleting staging deployment with id #{deployment.private_id} for cloud service #{cloud_srv_name}" cloud_srv_mgmt.delete_cloud_service_deployment(cloud_srv_name, "staging") ellapsed_time_min = (Time.now - start_time)/60.to_f puts "Deleting staging deployment #{deployment.private_id} for cloud service #{cloud_srv_name} done. Operation took #{ellapsed_time_min} minutes to complete".colorize(:green) else puts "No staging deployment detected for cloud service '#{cloud_srv_name}'".colorize(:magenta) end end
deploy_blob_pkg_to_staging(cloud_service_name, blob_pkg_name, pkg_dir, labels, options={})
click to toggle source
# File lib/quiverstaskrunner/azuresetup.rb, line 197 def deploy_blob_pkg_to_staging(cloud_service_name, blob_pkg_name, pkg_dir, labels, options={}) # 1. Load cloud service's details env = options[:env] || EnvHelper.get_env("env") timeout = options[:timeout] || 20*60 # 20 minutes update_message_on = is_update_message_on cloud_services = SettingsHelper.get_settings(File.join(Dir.pwd, @@secrets[:cloud_services]), env, @@get_settings_options) cloud_service_details = cloud_services[cloud_service_name] raise StandardError, "No details were found for cloud service #{cloud_service_name}" unless cloud_service_details # 2. Load storage details storage = SettingsHelper.get_settings(File.join(Dir.pwd, @@secrets[:storage]), env, @@get_settings_options) storage_details = storage["blob"] raise StandardError, "No details were found for blob storage for the #{env} environment" unless storage_details # 3. Configure the deployment details deployment_name = SecureRandom.uuid cloud_srv_name = cloud_service_details["name"] package_url = ENV["package_url"] if package_url.nil? if blob_pkg_name.nil? || blob_pkg_name.empty? raise ArgumentError, "Missing argument. No 'blob_pkg_name' or 'package_url' defined." else package_url = "https://#{storage_details['name']}.blob.core.windows.net/mydeployments/#{blob_pkg_name}" end end # This way of getting the service configuration file may seem weird(indeed, why not # using the standard File.open method?), but for some reasons that I don't understand, # File.open will result in a 'Bad Request : The specified configuration settings for Configuration # are invalid.' error service_configuration = XmlHelper.get_xml(File.join(pkg_dir, "ServiceConfiguration.#{env.capitalize}.cscfg")).to_xml deployment_options = { :slot => "staging", :label => labels, :start_deployment => true, :fire_and_forget => true, :upgrade_if_exists => true } # 4. Asynchronously deploy package to staging start_time = Time.now init_msg = nil cloud_srv_mgmt = Azure::CloudServiceManagementService.new no_error = true begin puts "Start deploying package from blob storage #{package_url} to cloud service" resp = cloud_srv_mgmt.create_deployment(deployment_name, cloud_srv_name, package_url, service_configuration, deployment_options) init_msg = "successfully initiated" rescue Exception => ex no_error = false init_msg = "failed" raise ex ensure ellapsed_time_min = (Time.now - start_time)/60.to_f puts "Deployment #{deployment_name} #{init_msg} after #{ellapsed_time_min} minutes" end # 5. Wait until the deployment is done deployment_pending = true waiting_start_time = Time.now timeout = timeout counter = 1 waiting_symbols = ["=", "+"] deployment_id = nil while deployment_pending do waiting_characters = Array.new(counter, waiting_symbols[0]).join if update_message_on print "\r" print "Waiting for confirmation of running instances #{waiting_characters}" end deployment = cloud_srv_mgmt.get_deployment(cloud_srv_name, {:slot => "staging" }) raise StandardError, "#{timeout} seconds timeout. Client unable to confirm operation success" if (Time.now - waiting_start_time) > timeout sleep 10 deployment_pending = !deployment.all_vms_running? || deployment.is_transitioning? deployment_id = deployment.private_id counter+=1 if counter > 40 counter = 1 waiting_symbols.reverse! end end print "\n" ellapsed_time_min = (Time.now - start_time)/60.to_f puts "Deployment #{deployment_name} with id #{deployment_id} running successfully. Deployment took #{ellapsed_time_min} minutes to complete".colorize(:green) return no_error end
is_update_message_on()
click to toggle source
# File lib/quiverstaskrunner/azuresetup.rb, line 37 def is_update_message_on update_message_on = true begin update_message_on = (EnvHelper.get_env("update_message_on") == "true") rescue update_message_on = true end return update_message_on end
list_secrets()
click to toggle source
# File lib/quiverstaskrunner/azuresetup.rb, line 47 def list_secrets() if (defined? ARGV) && (!ARGV.detect { |x| x.index("secrets") == 0 }) puts "usage: rake list secrets=<args> env=<args>".colorize(:yellow) puts puts "This task lists the secrets key value pairs for a specific environment. The optional parameter 'secrets' allows to filter the results.".colorize(:yellow) puts "The 'secrets' option is used as follow:".colorize(:yellow) puts " rake list secrets=cloud_services env=test".colorize(:yellow) puts "where 'cloud_services' represents all the key value pairs associated with Windows Azure Cloud Services.".colorize(:yellow) puts "It is possible to define multiple secrets type by using the '/' separator as follow:".colorize(:yellow) puts " rake list secrets=cloud_services/storage env=test".colorize(:yellow) puts puts "Allowed secret types are:".colorize(:yellow) puts " all => List all secret types".colorize(:yellow) puts " cloud_services => List secrets about the Windows Azure Cloud Services".colorize(:yellow) puts " storage => List secrets about the Windows Azure Storage".colorize(:yellow) puts " certs => List all SSL certs currently set up for the consumer pages".colorize(:yellow) puts " global => List various common global settings used across all Quivers project".colorize(:yellow) puts puts "Allowed environments are:".colorize(:yellow) puts " test".colorize(:yellow) puts " demo".colorize(:yellow) puts " prod".colorize(:yellow) else cli_hash = SettingsHelper.get_cli_settings() secrets_list = cli_hash["secrets"] white_list = if (!secrets_list.nil?) && (!secrets_list.empty?) && (secrets_list != "all") white_list = secrets_list .split('/') .reject { |x| !@@allowed_secret_types.detect { |k,v| k == x } } .map { |x| @@allowed_secret_types[x] } elsif secrets_list == "all" [ :all ] else nil end if (!white_list.nil?) env = env || EnvHelper.get_env("env") if white_list[0] != :all @@secrets .reject { |k,v| !white_list.detect { |x| k == x } } .each do |k,v| puts "#{k}".colorize(:yellow) puts puts CliHelper.pretty_print(SettingsHelper.get_settings(File.join(Dir.pwd, v), env, @@get_settings_options)) end else @@secrets .each do |k,v| puts "#{k}".colorize(:yellow) puts puts CliHelper.pretty_print(SettingsHelper.get_settings(File.join(Dir.pwd, v), env, @@get_settings_options)) end end else raise StandardError, "None of the provided secrets matches any allowed secret types. Run 'rake list -cs' to get the usage" end end end
replace_tokens(files_with_missing_tokens, tokens)
click to toggle source
# File lib/quiverstaskrunner/replacetokens.rb, line 4 def replace_tokens(files_with_missing_tokens, tokens) files = files_with_missing_tokens.is_a?(Array) ? files_with_missing_tokens : [files_with_missing_tokens] raise ArgumentError, "'tokens' must be a Hash" unless tokens.is_a?(Hash) files.each { |f_path| content = nil File.open(f_path, "rb") do |f| content = f.read tokens.each { |k,v| content = content.gsub("{{#{k}}}", v) } end File.open(f_path, "w") do |f| f.write(content) end } end
restore_and_clean_files(files_to_restore)
click to toggle source
# File lib/quiverstaskrunner/restorepoints.rb, line 23 def restore_and_clean_files(files_to_restore) # convert single file into an array files = files_to_restore.is_a?(Array) ? files_to_restore : (files_to_restore.nil? ? [] : [files_to_restore]) files.each do |f| f_ext = File.extname(f) f_backup_ext = ".backup#{f_ext}" f_backup = f.gsub(f_ext, f_backup_ext) # 1. Make sure there are restore files available raise StandardError, "Missing restore file #{f_backup}" unless FileTest.exists? f_backup # 2. Delete the modified files FileUtils.rm_f(f) # 3. Restore modified files FileUtils.cp f_backup, f # 4. Delete backup files FileUtils.rm_f(f_backup) end end
scale_host(cloud_service_name, service_configuration, service_definition, env=nil)
click to toggle source
# File lib/quiverstaskrunner/azuresetup.rb, line 108 def scale_host(cloud_service_name, service_configuration, service_definition, env=nil) env = env || EnvHelper.get_env("env") # 1. Get cloud service's details cloud_services = SettingsHelper.get_settings(File.join(Dir.pwd, @@secrets[:cloud_services]), env, @@get_settings_options) cloud_service_details = cloud_services[cloud_service_name] raise StandardError, "No details were found for cloud service #{cloud_service_name}" unless cloud_service_details vmsize = cloud_service_details["vmsize"] vmnbr = cloud_service_details["vmnbr"] # 2. Load xml files service_config_xml = XmlHelper.get_xml(service_configuration) service_def_xml = XmlHelper.get_xml(service_definition) service_config_xml.update_node_at_css_selector('ServiceConfiguration Role Instances', { :count => vmnbr }) service_def_xml.update_node_at_css_selector('ServiceDefinition WebRole', { :vmsize => vmsize }) XmlHelper.overide_xml(service_configuration, service_config_xml) XmlHelper.overide_xml(service_definition, service_def_xml) end
swap(cloud_service_name, options={})
click to toggle source
# File lib/quiverstaskrunner/azuresetup.rb, line 283 def swap(cloud_service_name, options={}) # 1. Load cloud service's details env = options[:env] || EnvHelper.get_env("env") timeout = options[:timeout] || 20*60 # 20 minutes update_message_on = is_update_message_on cloud_services = SettingsHelper.get_settings(File.join(Dir.pwd, @@secrets[:cloud_services]), env, @@get_settings_options) cloud_service_details = cloud_services[cloud_service_name] cloud_srv_name = cloud_service_details["name"] # 2. Asynchronously swap deployments start_time = Time.now init_msg = nil cloud_srv_mgmt = Azure::CloudServiceManagementService.new no_error = true begin puts "Start swapping deployments for cloud service '#{cloud_srv_name}'" resp = cloud_srv_mgmt.swap_deployment(cloud_srv_name, {:fire_and_forget => true}) init_msg = "successfully initiated" rescue Exception => ex no_error = false init_msg = "failed" raise ex ensure ellapsed_time_min = (Time.now - start_time)/60.to_f puts "Swapping deployments for cloud service '#{cloud_srv_name}' #{init_msg} after #{ellapsed_time_min} minutes" end # 3. Wait until the swapping is done deployment_pending = true waiting_start_time = Time.now counter = 1 waiting_symbols = ["=", "+"] while deployment_pending do waiting_characters = Array.new(counter, waiting_symbols[0]).join if update_message_on print "\r" print "Waiting for confirmation of running instances #{waiting_characters}" end deployment = cloud_srv_mgmt.get_deployment(cloud_srv_name, {:slot => "production" }) raise StandardError, "#{timeout} seconds timeout. Client unable to confirm operation success" if (Time.now - waiting_start_time) > timeout sleep 10 deployment_pending = !deployment.all_vms_running? || deployment.is_transitioning? counter+=1 if counter > 40 counter = 1 waiting_symbols.reverse! end end print "\n" ellapsed_time_min = (Time.now - start_time)/60.to_f puts "Swapping deployments for cloud service '#{cloud_srv_name}' done. Swapping took #{ellapsed_time_min} minutes to complete".colorize(:green) return no_error end
upload_cspkg_to_blob(pkg_name, pkg_dir, options={})
click to toggle source
# File lib/quiverstaskrunner/azuresetup.rb, line 152 def upload_cspkg_to_blob(pkg_name, pkg_dir, options={}) # 1. Configure the blob object, and load the package inside it timeout = options[:timeout] || 20*60 # 20 minutes blob_srv = Azure::Blob::BlobService.new blob_name = Time.now.utc.strftime("%Y%m%d_%H%M%S_#{pkg_name}") blob_container = "mydeployments" block_list = [] counter = 1 File.open(File.join(pkg_dir, pkg_name), "rb") do |f| f.each_chunk {|chunk| block_id = counter.to_s.rjust(5, '0') block_list << [block_id, :uncommitted] blob_options = { :content_md5 => Base64.strict_encode64(Digest::MD5.digest(chunk)), :content_type => "application/octet-stream", :timeout => timeout } md5 = blob_srv.create_blob_block(blob_container, blob_name, block_id, chunk, blob_options) counter += 1 } end # 2. Upload the blob object to the blob storage start_time = Time.now uploaded_package_name = nil no_error = true begin puts "Start uploading package #{blob_name} to blob storage" #new_blob = blob_srv.create_block_blob(blob_container, blob_name, blob_content, blob_options) blob_srv.commit_blob_blocks(blob_container, blob_name, block_list) uploaded_package_name = blob_name rescue Exception => ex no_error = false raise ex ensure ellappsed_min = (Time.now - start_time)/60.to_f puts "Upload of package #{blob_name} to blob storage succeeded in #{ellappsed_min} minutes".colorize(:green) end return [uploaded_package_name, no_error] end