class Transform

Constants

APPCLIENTID
APPIDURI
CONNECTIONSTRING
EMPTY_STR
NEWRELIC_APPNAME
NO_VALUE
OLDAPPID
ROWKEY
SERVICENAME
SETTING
STORAGEACCOUNT
STORAGEACCOUNTKEY
VALUE

Attributes

config_files[RW]
debug_mode[RW]
env[RW]
settings[RW]
svc[RW]
table[RW]

Public Instance Methods

get(key) click to toggle source
# File lib/transform.rb, line 24
def get key
  begin
    result = @svc.get_entity @table, @env, key
  rescue
    puts $!
    puts "Error retrieving key: #{@key}"
    puts
  end

  result
end
get_all() click to toggle source
# File lib/transform.rb, line 36
def get_all
  begin
    query = { :filter => "PartitionKey eq '#{@env}'" }
    result = @svc.query_entities @table, query
  rescue
    puts $!
    puts "Error retrieving table entities for Env : #{@env}"
    puts
  end

  result
end
get_value(key) click to toggle source
# File lib/transform.rb, line 49
def get_value key
  if @settings.nil?
    return
  end
  value = EMPTY_STR
  @settings.each { |i|
    if i.properties[ROWKEY] == key
      value = i.properties[SETTING]
      break
    end
  }

  value
end
remove_paths_from_list(paths_to_exclude, source_list) click to toggle source
# File lib/transform.rb, line 433
def remove_paths_from_list paths_to_exclude, source_list
  paths_to_exclude.each { |path|
    source_list.delete_if { |file|
      file.include? path
    }
  }
end
transform(paths_to_exclude = []) click to toggle source

paths_to_exclude is array of partial or full paths of projects where transform needs skipped

# File lib/transform.rb, line 442
def transform paths_to_exclude = []

  @debug_mode = ENV['transform_debug_mode']

  # --- Get environment invoked
  @env = ENV['env'] || NO_VALUE
  if @env == NO_VALUE
    puts 'Environment name required to transform. No configuration changes will be done...'
    return false
  else
    puts "Transforming config for environment: #{@env} ..."
  end

  # --- Get Settings Account Name, Key and Table from Environment variables
  settings_account_name = ENV['SettingsAccount'] || ENV[STORAGEACCOUNT] || NO_VALUE
  if settings_account_name == NO_VALUE
    puts "No settings storage account name found"
    return false
  end
  settings_access_key = ENV['SettingsAccountKey'] || ENV[STORAGEACCOUNTKEY] || NO_VALUE
  if settings_access_key == NO_VALUE
    puts "No settings storage account key found"
    return false
  end
  config_table = ENV['ConfigSettingsTable'] || NO_VALUE
  if config_table == NO_VALUE
    puts "No configuration table found"
  end

  # --- Collect config files to transform
  # find all App.config and web.config files
  @config_files = Dir.glob '**/app.config'
  @config_files.concat(Dir.glob '**/appSettings.config')
  @config_files.concat(Dir.glob '**/web.config')
  @config_files.concat(Dir.glob '**/RuntimeWeb/*Web.dll.config')
  @config_files.concat(Dir.glob '**/RuntimeService/*.exe.config')

  # remove projects which need not be transformed
  remove_paths_from_list paths_to_exclude, @config_files

  # --- Load Settings from storage
  # azure table storage account where settings reside
  Azure.config.storage_account_name = settings_account_name
  Azure.config.storage_access_key = settings_access_key
  @table = config_table

  # table service
  @svc = Azure::TableService.new

  # get all settings for environment
  @settings = get_all

  # --- Start Transformations ---
  puts "updating settings #{CONNECTIONSTRING}..."
  settings_connstr = "DefaultEndpointsProtocol=https;AccountName=#{settings_account_name};AccountKey=#{settings_access_key}"
  should_update_settings_connstr = ENV['should_update_settings_connstr'] || NO_VALUE
  if should_update_settings_connstr == NO_VALUE
    puts "Flag for Setttings #{CONNECTIONSTRING} Update not set."
  else
    transform_appsettings CONNECTIONSTRING, settings_connstr
  end

  puts "updating unit test #{CONNECTIONSTRING}..."
  unitest_connstr = ENV["unitest#{CONNECTIONSTRING}"] || NO_VALUE
  if unitest_connstr == NO_VALUE
    puts "No unit test #{CONNECTIONSTRING} found."
  else
    transform_appsettings "unitest#{CONNECTIONSTRING}", unitest_connstr
  end

  puts "updating #{APPCLIENTID}..."
  appClientId = ENV[APPCLIENTID] || NO_VALUE
  if appClientId == NO_VALUE
    puts "No #{APPCLIENTID} found."
    # old version notify check
    oldAppId = ENV[OLDAPPID]
    if oldAppId != NO_VALUE
      puts "You appear to be using the old AppId environment variable, AppClientId is expected. Proceeding with old AppId update."
      transform_appsettings OLDAPPID, oldAppId
    end
  else
    transform_appsettings APPCLIENTID, appClientId
  end

  puts "updating #{APPIDURI}..."
  appIdUri = ENV[APPIDURI] || NO_VALUE
  if appIdUri == NO_VALUE
    puts "No #{APPIDURI} found."
  else
    transform_appsettings APPIDURI, appIdUri
  end

  @service_name = ENV[SERVICENAME]
  is_service = @service_name || NO_VALUE
  if is_service != NO_VALUE
    puts "Transforming config for service: #{@service_name}"

    puts 'Obtaining cloud configuration templates...'
    csdefTemplate = get_value 'ServiceDefinitionTemplate'
    File.write 'ServiceDefinition.csdef', csdefTemplate
    cscfgTemplate = get_value 'ServiceConfigurationTemplate'
    File.write 'ServiceConfiguration.cscfg', cscfgTemplate

    puts 'Transforming csdef...'
    xml_node_processing = nil
    use_riverbed = ENV['UseRiverbed'] || NO_VALUE
    use_riverbed = use_riverbed.downcase
    if use_riverbed == "true"
      puts 'Using riverbed...'
      xml_node_processing = method(:transform_riverbed)
    end
    use_newrelic = ENV['UseNewrelic'] || NO_VALUE
    use_newrelic = use_newrelic.downcase
    if use_newrelic == "true"
      puts 'Using new relic...'
      transform_appsettings NEWRELIC_APPNAME, @service_name
      xml_node_processing = method(:transform_newrelic)
    end
    use_appdynamics = ENV['UseAppdynamics'] || NO_VALUE
    use_appdynamics = use_appdynamics.downcase
    if use_appdynamics == "true"
      puts 'Using app dynamics...'
      xml_node_processing = method(:transform_appdynamics)
      transform_appdynamics_config
    end

    if !((use_riverbed == "true" and use_newrelic != "true" and use_appdynamics != "true") or
      (use_riverbed != "true" and use_newrelic == "true" and use_appdynamics != "true") or
      (use_riverbed != "true" and use_newrelic != "true" and use_appdynamics == "true") or
      (use_riverbed != "true" and use_newrelic != "true" and use_appdynamics != "true"))
      puts 'Only one APM tool can be used at one time, aborting.'
      return false
    end


    transform_csdef xml_node_processing

    puts 'Transforming cscfg...'
    transform_cscfg

    puts 'Transforming diagnostics cfg...'
    transform_diagnosticscfg

    puts 'Replacing service model settings...'
    transform_servicemodelconfig
  else
    puts 'Target to transform is not a service...'
  end

  puts 'Replacing app settings...'
  transform_appsettings

  puts 'Removing debug compilation attributes...'
  transform_systemwebcompilationattribs

  puts 'Transforming cache client...'
  transform_cacheclient

  puts 'Transforming Application Insights...'
  transform_appinsights paths_to_exclude

  puts 'Transforming log4net config...'
  transform_log4net

  return true
end
transform_appdynamics(doc) click to toggle source
# File lib/transform.rb, line 289
def transform_appdynamics doc
  is_service = @service_name || NO_VALUE
  if is_service != NO_VALUE
    node = doc.at_css 'WebRole'
    transform_appdynamics_node(doc, node) if !node.nil?
    node = doc.at_css 'WorkerRole'
    transform_appdynamics_node(doc, node) if !node.nil?
  else
    puts 'Not a service, avoiding transforming the csdef.'
  end
end
transform_appdynamics_config() click to toggle source
# File lib/transform.rb, line 70
def transform_appdynamics_config
  # update application name in the config.xml
  puts 'Transforming appdynamics config.'
  files = Dir.glob '**/RuntimeService/AppDynamics/config.xml'
  transform_xmlsettings(files, nil, method(:update_appdynamics_application), 'name', @service_name)
end
transform_appdynamics_node(doc, xml_node) click to toggle source
# File lib/transform.rb, line 301
def transform_appdynamics_node doc, xml_node
  task_node = Nokogiri::XML::Node.new 'Task', doc

  task_node['commandLine'] = "AppDynamics\\startup_env.cmd"
  task_node['executionContext'] = 'elevated'
  task_node['taskType'] = 'simple'

  env_node = Nokogiri::XML::Node.new 'Environment', doc
  var_node = Nokogiri::XML::Node.new 'Variable', doc
  var_node['name'] = 'EMULATED'
  val_node = Nokogiri::XML::Node.new 'RoleInstanceValue', doc
  val_node['xpath'] = '/RoleEnvironment/Deployment/@emulated'

  var_node.add_child(val_node)
  env_node.add_child(var_node)
  task_node.add_child(env_node)

  existing_start_up_node = xml_node.at_css('Startup')
  if existing_start_up_node.nil?
    start_up_node = Nokogiri::XML::Node.new 'Startup', doc
    xml_node.add_child(start_up_node)
    start_up_node.add_child(task_node)
  else
    existing_start_up_node.add_child(task_node)
  end
end
transform_appinsights(paths_to_exclude) click to toggle source
# File lib/transform.rb, line 352
def transform_appinsights paths_to_exclude
  aiconfig = Dir.glob '**/ApplicationInsights.config'

  remove_paths_from_list paths_to_exclude, aiconfig

  aiconfig.each{ |file|
    doc = Nokogiri::XML(File.read file)

    node = doc.at_css 'InstrumentationKey'
    if !node.nil?
      val_from_settings = get_value 'AI_InstrumentationKey'
      if val_from_settings.to_s == EMPTY_STR
        aikey =  ENV['AI_InstrumentationKey'] || NO_VALUE
      else
        aikey = val_from_settings
      end
      if aikey != NO_VALUE
        node.content = aikey
      end
    end

    File.write file, doc.to_xml
  }
end
transform_appsettings(key = EMPTY_STR, value = EMPTY_STR) click to toggle source
# File lib/transform.rb, line 64
def transform_appsettings key = EMPTY_STR, value = EMPTY_STR
  # go to each file and replace value of matching appSettings key
  puts 'Transforming app settings.'
  transform_xmlsettings(@config_files, @settings, method(:update_appsetting), key, value)
end
transform_cacheclient() click to toggle source
# File lib/transform.rb, line 392
def transform_cacheclient
  cacheclient_id = get_value 'CacheClient_Identifier'
  @config_files.each{ |file|
    doc = Nokogiri::XML(File.read file)

    node = doc.at_css 'dataCacheClients/dataCacheClient/autoDiscover'
    if !node.nil?
      node['identifier'] = cacheclient_id
    end

    File.write file, doc.to_xml
  }
end
transform_cscfg() click to toggle source
# File lib/transform.rb, line 328
def transform_cscfg

  csdef = Dir.glob '**/*.cscfg'
  csdef.each{ |file|
    doc = Nokogiri::XML(File.read file)

    node = doc.at_css 'ServiceConfiguration'
    node['serviceName'] = @service_name if !node.nil?

    node = doc.at_css 'Role'
    node['name'] = @service_name if !node.nil?

    node = doc.at_css 'Certificates'

    node.replace(get_value 'Certificates_cscfg') if !node.nil?

    node = doc.at_css 'ConfigurationSettings'
    node.replace(get_value 'ConfigurationSettings_cscfg') if !node.nil?

    File.write file, doc.to_xml
  }
end
transform_csdef(custom_xml_process=nil) click to toggle source
# File lib/transform.rb, line 169
def transform_csdef custom_xml_process=nil
  csdef = Dir.glob '**/*.csdef'
  csdef.each{ |file|
    doc = Nokogiri::XML(File.read file)

    node = doc.at_css 'ServiceDefinition'
    node['name'] = @service_name if !node.nil?

    node = doc.at_css 'WebRole'
    node['name'] = @service_name if !node.nil?

    node = doc.at_css 'WorkerRole'
    node['name'] = @service_name if !node.nil?

    node = doc.at_css 'Certificates'

    node.replace(get_value 'Certificates_csdef') if !node.nil?

    node = doc.at_css 'Endpoints'
    node.replace(get_value 'Endpoints') if !node.nil?

    node = doc.at_css 'Bindings'
    node.replace(get_value 'Bindings') if !node.nil?

    node = doc.at_css 'Sites'
    node.replace(get_value 'Sites') if !node.nil?

    node = doc.at_css 'Imports'
    node.replace(get_value 'Imports') if !node.nil?

    node = doc.at_css 'LocalResources'
    node.replace(get_value 'LocalResources') if !node.nil?

    custom_xml_process.call(doc) if !custom_xml_process.nil? and !doc.nil?

    File.write file, doc.to_xml

  }
end
transform_diagnosticscfg() click to toggle source
# File lib/transform.rb, line 377
def transform_diagnosticscfg
  csdef = Dir.glob '**/*.wadcfgx'
  csdef.each{ |file|
    doc = Nokogiri::XML(File.read file)

    node = doc.at_css "PrivateConfig/#{STORAGEACCOUNT}"
    node['name'] = get_value STORAGEACCOUNT
    node['key'] = get_value STORAGEACCOUNTKEY
    node = doc.at_css STORAGEACCOUNT
    node.content = get_value STORAGEACCOUNT

    File.write file, doc.to_xml
  }
end
transform_log4net() click to toggle source

log level and azure table appender parameters are transformed

# File lib/transform.rb, line 407
def transform_log4net
  config_files = Dir.glob '**/log4net.config'
  config_files.each{ |file|
    doc = Nokogiri::XML(File.read file)

    # azure table name is service name
    node = doc.at_css 'log4net/appender[@name=AzureTableAppender]/param[@name=TableName]'
    node['value'] = @service_name if !node.nil?

    node = doc.at_css 'log4net/appender[@name=AzureTableAppender]/param[@name=ConnectionString]'
    log_connstr = ENV["log#{CONNECTIONSTRING}"] || NO_VALUE
    if log_connstr == NO_VALUE
      puts "No logging #{CONNECTIONSTRING} found."
    else
      node['value'] = log_connstr if !node.nil?
    end

    # log level
    node = doc.at_css 'log4net/root/level'
    loglevel = ENV['loglevel'] || NO_VALUE
    node['value'] = ENV['loglevel'] if (!node.nil? && loglevel != NO_VALUE)

    File.write file, doc.to_xml
  }
end
transform_newrelic(doc) click to toggle source
# File lib/transform.rb, line 250
def transform_newrelic doc
  is_service = @service_name || NO_VALUE
  if is_service != NO_VALUE
    node = doc.at_css 'WebRole'
    transform_newrelic_node(doc, node) if !node.nil?
    node = doc.at_css 'WorkerRole'
    transform_newrelic_node(doc, node) if !node.nil?
  else
    puts 'Not a service, avoiding transforming the csdef.'
  end
end
transform_newrelic_node(doc, xml_node) click to toggle source
# File lib/transform.rb, line 262
def transform_newrelic_node doc, xml_node
  task_node = Nokogiri::XML::Node.new 'Task', doc

  task_node['commandLine'] = 'newrelic_env.cmd'
  task_node['executionContext'] = 'elevated'
  task_node['taskType'] = 'simple'

  env_node = Nokogiri::XML::Node.new 'Environment', doc
  var_node = Nokogiri::XML::Node.new 'Variable', doc
  var_node['name'] = 'EMULATED'
  val_node = Nokogiri::XML::Node.new 'RoleInstanceValue', doc
  val_node['xpath'] = '/RoleEnvironment/Deployment/@emulated'

  var_node.add_child(val_node)
  env_node.add_child(var_node)
  task_node.add_child(env_node)

  existing_start_up_node = xml_node.at_css('Startup')
  if existing_start_up_node.nil?
    start_up_node = Nokogiri::XML::Node.new 'Startup', doc
    xml_node.add_child(start_up_node)
    start_up_node.add_child(task_node)
  else
    existing_start_up_node.add_child(task_node)
  end
end
transform_riverbed(doc) click to toggle source
# File lib/transform.rb, line 209
def transform_riverbed doc
  is_service = @service_name || NO_VALUE
  if is_service != NO_VALUE
    node = doc.at_css 'WebRole'
    transform_riverbed_node(doc, node) if !node.nil?
    node = doc.at_css 'WorkerRole'
    transform_riverbed_node(doc, node) if !node.nil?
  else
    puts 'Not a service, avoiding transforming the csdef.'
  end
end
transform_riverbed_node(doc, xml_node) click to toggle source
# File lib/transform.rb, line 221
def transform_riverbed_node doc, xml_node
  task_node = Nokogiri::XML::Node.new 'Task', doc

  task_node['commandLine'] = 'AppInternals\startup.cmd'
  task_node['executionContext'] = 'elevated'
  task_node['taskType'] = 'foreground'

  env_node = Nokogiri::XML::Node.new 'Environment', doc
  var_node = Nokogiri::XML::Node.new 'Variable', doc
  var_node['name'] = 'AnalysisServerIP'
  var_node['value'] = get_value 'AnalysisServerIP'
  var_node2 = Nokogiri::XML::Node.new 'Variable', doc
  var_node2['name'] = 'AgentInstaller'
  var_node2['value'] = get_value 'AgentInstaller'

  env_node.add_child(var_node)
  env_node.add_child(var_node2)
  task_node.add_child(env_node)

  existing_start_up_node = xml_node.at_css('Startup')
  if existing_start_up_node.nil?
    start_up_node = Nokogiri::XML::Node.new 'Startup', doc
    xml_node.add_child(start_up_node)
    start_up_node.add_child(task_node)
  else
    existing_start_up_node.add_child(task_node)
  end
end
transform_servicemodelconfig() click to toggle source
# File lib/transform.rb, line 137
def transform_servicemodelconfig
  @config_files.each{|file|
    doc = Nokogiri::XML(File.read file)
    doc.xpath('//system.serviceModel').each do |node|
      if !node.nil?
        if file.end_with?('app.config') || file.end_with?('App.config')
          val = get_value 'system.ServiceModel.Client'
          node.replace val if !val.nil?
        elsif file.end_with?('Web.config')
          val = get_value 'system.ServiceModel.Service'
          node.replace val if !val.nil?
        end
        File.write file, doc.to_xml
      end
    end
  }
end
transform_systemwebcompilationattribs() click to toggle source
# File lib/transform.rb, line 155
def transform_systemwebcompilationattribs
  @config_files.each{|file|
    doc = Nokogiri::XML(File.read file)
    node = doc.at_css 'compilation'
    if !node.nil?
      #puts node
      node.xpath('//@debug').remove
      node.xpath('//@tempDirectory').remove
      #puts node
      File.write file, doc.to_xml
    end
  }
end
transform_xmlsettings(files, settings, update_setting, key = EMPTY_STR, value = EMPTY_STR) click to toggle source
# File lib/transform.rb, line 77
def transform_xmlsettings files, settings, update_setting, key = EMPTY_STR, value = EMPTY_STR
  files.each{|file|
    doc = Nokogiri::XML(File.read file)
    puts "Processing file: #{file}"
    if (key.to_s != EMPTY_STR && value.to_s != EMPTY_STR)
      k = key
      v = value
      status = update_setting.call(k, v, doc, file)
      if status == :updated
        if @debug_mode
          puts "Updated key #{k} with #{v}"
        else
          puts "Updated key: #{k}"
        end
      end
    else
      if !settings.nil?
        settings.each { |i|
          k = i.properties[ROWKEY] || NO_VALUE
          v = i.properties[SETTING] || NO_VALUE
          status = update_setting.call(k, v, doc, file)
          if status == :updated
            if @debug_mode
              puts "Updated key #{k} with #{v}"
            else
              puts "Updated key: #{k}"
            end
          end
        }
      end
    end
  }
end
update_appdynamics_application(k, v, doc, file) click to toggle source
# File lib/transform.rb, line 115
def update_appdynamics_application k, v, doc, file
  update_xmlsetting(k, v, doc, file, "controller/application", k)
end
update_appsetting(k, v, doc, file) click to toggle source
# File lib/transform.rb, line 111
def update_appsetting k, v, doc, file
  update_xmlsetting(k, v, doc, file, "appSettings/add[@key='#{k}']")
end
update_xmlsetting(k, v, doc, file, xpath, value_key = VALUE) click to toggle source
# File lib/transform.rb, line 119
def update_xmlsetting k, v, doc, file, xpath, value_key = VALUE
  status = :noargs
  if (k != NO_VALUE && v != NO_VALUE)
    node = doc.at_css xpath
    if !node.nil?
      puts "Old value: #{node[value_key]}" if @debug_mode
      node[value_key] = v
      puts "New value: #{v}" if @debug_mode
      File.write file, doc.to_xml
      status = :updated
    else
      status = :notfound
    end
  end

  status
end