Skip to content

Instantly share code, notes, and snippets.

@mpage
Created May 16, 2012 20:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpage/2713646 to your computer and use it in GitHub Desktop.
Save mpage/2713646 to your computer and use it in GitHub Desktop.
require "digest/md5"
require "logger"
require "tmpdir"
require "vmc"
# These are actually vmc requires
require "cli/config"
require "cli/zip_util"
def create_app_name
"nfs_race-" + Digest::MD5.hexdigest(Time.now.to_s)
end
def create_dummy_app(app_name)
base_dir = Dir.mktmpdir
app_contents =<<EOT
require "sinatra"
get "/" do
"HELLO! from #{app_name} created at #{Time.now}"
end
EOT
test_file = File.join(base_dir, "test.rb")
File.open(test_file, "w+") { |f| f.write(app_contents) }
base_dir
end
def create_resource_manifest(app_path)
fingerprints = []
resource_files = Dir.glob("#{app_path}/**/*", File::FNM_DOTMATCH)
resource_files.each do |filename|
next if (File.directory?(filename) || !File.exists?(filename))
fingerprints << {
:size => File.size(filename),
:sha1 => Digest::SHA1.file(filename).hexdigest,
:fn => filename
}
end
fingerprints
end
if ARGV.size != 4
puts "Usage: nfs_race_repro.rb <cc ip> <different cc ip> <user> <pass>"
exit 1
end
cc_a, cc_b, user, pass = ARGV
logger = Logger.new(STDOUT)
logger.level = Logger::INFO
vmcs = [cc_a, cc_b].map do |cc_ip|
logger.info("Logging in to #{cc_ip}")
vmc = VMC::Client.new("http://#{cc_ip}:9022")
vmc.login(user, pass)
logger.info("Success")
vmc
end
work_dir = Dir.mktmpdir
app_manifest = {
:staging => {
:framework => "sinatra",
:runtime => nil,
},
:resources => {
:memory => 64
}
}
app_name = create_app_name
app_path = create_dummy_app(app_name)
begin
logger.info("Creating app (#{app_name}) on #{vmcs[0].target}")
vmcs[0].create_app(app_name, app_manifest)
app_created = true
# Check resources on one CC. This should prime the dentry cache with negative
# entries.
logger.info("Checking resources on #{vmcs[0].target}")
resource_manifest = create_resource_manifest(app_path)
existing_resources = vmcs[0].check_resources(resource_manifest)
if existing_resources.size > 0
# Should always need to upload, since our file has a unique-ish string in it
raise "CC should not have any of our resources. Has #{existing_resources}"
end
# Upload on the other CC. The dentry cache on the first CC should still have
# negative entries, while this CC will end up with positive ones.
logger.info("Uploading app to #{vmcs[1].target}")
app_zipfile_path = File.join(work_dir, "#{app_name}.zip")
VMC::Cli::ZipUtil.pack(app_path, app_zipfile_path)
vmcs[1].upload_app(app_name, app_zipfile_path, existing_resources)
# Check resources on the CC we just uploaded to. It should have the files
# we just uploaded in the resource pool now and will tell us that we do not
# need to upload them.
logger.info("Checking resources on #{vmcs[1].target}")
existing_resources = vmcs[1].check_resources(resource_manifest)
if existing_resources.size != 1
raise "CC should have our resources. Has #{existing_resources} instead."
end
# Upload to the CC with the negative dentry cache entries. This should fail
# with an AppPackaging error.
logger.info("Uploading app to #{vmcs[0].target}")
# Copied directly from VMC
existing_resources.each do |resource|
logger.info("Removing #{resource[:fn]}")
FileUtils.rm_f resource[:fn]
# adjust filenames sans the explode_dir prefix
resource[:fn].sub!("#{app_path}/", '')
end
if VMC::Cli::ZipUtil.get_files_to_pack(app_path).empty?
Dir.chdir(app_path) do
File.new(".__empty__", "w")
end
end
app_zipfile_path = File.join(work_dir, "#{app_name}.zip")
FileUtils.rm(app_zipfile_path)
VMC::Cli::ZipUtil.pack(app_path, app_zipfile_path)
vmcs[0].upload_app(app_name, app_zipfile_path, existing_resources)
ensure
if app_created
logger.info("Deleting #{app_name}")
vmcs[0].delete_app(app_name)
end
if app_path
logger.info("Removing app locally")
FileUtils.rm_rf(app_path)
end
if work_dir
logger.info("Removing work dir")
FileUtils.rm_rf(work_dir)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment