bento-lpn 1.1.3

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.
@@ -0,0 +1,105 @@
1
+ require "benchmark"
2
+ require "fileutils"
3
+ require "json"
4
+ require "tempfile"
5
+ require "yaml"
6
+ require "vagrant_cloud"
7
+
8
+ MEGABYTE = 1024.0 * 1024.0
9
+
10
+ module Common
11
+ def vc_account
12
+ VagrantCloud::Account.new(ENV["VAGRANT_CLOUD_ORG"], ENV["VAGRANT_CLOUD_TOKEN"])
13
+ end
14
+
15
+ def banner(msg)
16
+ puts "==> #{msg}"
17
+ end
18
+
19
+ def info(msg)
20
+ puts " #{msg}"
21
+ end
22
+
23
+ def warn(msg)
24
+ puts ">>> #{msg}"
25
+ end
26
+
27
+ def duration(total)
28
+ total = 0 if total.nil?
29
+ minutes = (total / 60).to_i
30
+ seconds = (total - (minutes * 60))
31
+ format("%dm%.2fs", minutes, seconds)
32
+ end
33
+
34
+ def box_metadata(metadata_file)
35
+ metadata = Hash.new
36
+ file = File.read(metadata_file)
37
+ json = JSON.parse(file)
38
+
39
+ # metadata needed for upload: boxname, version, provider, box filename
40
+ metadata["name"] = json["name"]
41
+ metadata["version"] = json["version"]
42
+ metadata["box_basename"] = json["box_basename"]
43
+ metadata["tools"] = json["tools"]
44
+ metadata["providers"] = Hash.new
45
+ json["providers"].each do |provider|
46
+ metadata["providers"][provider["name"]] = provider.reject { |k, _| k == "name" }
47
+ end
48
+ metadata
49
+ end
50
+
51
+ def metadata_files
52
+ @metadata_files ||= compute_metadata_files
53
+ end
54
+
55
+ def compute_metadata_files
56
+ `ls builds/*.json`.split("\n")
57
+ end
58
+
59
+ def builds_yml
60
+ YAML.load(File.read("builds.yml"))
61
+ end
62
+
63
+ def build_list
64
+ bit32 = []
65
+ bit64 = []
66
+ builds_yml["public"].each do |platform, versions|
67
+ versions.each do |version, archs|
68
+ archs.each do |arch|
69
+ folder = case platform
70
+ when "opensuse-leap"
71
+ "opensuse"
72
+ when "oracle"
73
+ "oraclelinux"
74
+ else
75
+ platform
76
+ end
77
+ case arch
78
+ when "i386"
79
+ bit32 << "#{folder}/#{platform}-#{version}-#{arch}"
80
+ else
81
+ bit64 << "#{folder}/#{platform}-#{version}-#{arch}"
82
+ end
83
+ end
84
+ end
85
+ end
86
+ bit64 + bit32
87
+ end
88
+
89
+ def private_box?(boxname)
90
+ proprietary_os_list = %w{macos windows sles solaris rhel}
91
+ proprietary_os_list.any? { |p| boxname.include?(p) }
92
+ end
93
+
94
+ def os_x?
95
+ !!(RUBY_PLATFORM =~ /darwin/)
96
+ end
97
+
98
+ def unix?
99
+ !windows?
100
+ end
101
+
102
+ def windows?
103
+ !!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
104
+ end
105
+ end
@@ -0,0 +1,22 @@
1
+ require "bento/common"
2
+
3
+ class DeleteRunner
4
+ include Common
5
+
6
+ attr_reader :box, :version
7
+
8
+ def initialize(opts)
9
+ @box = opts.box
10
+ @version = opts.version
11
+ end
12
+
13
+ def start
14
+ banner("Starting Delete...")
15
+ time = Benchmark.measure do
16
+ box = vc_account.get_box(box)
17
+ version = box.get_version(version)
18
+ version.delete
19
+ end
20
+ banner("Delete finished in #{duration(time.real)}.")
21
+ end
22
+ end
@@ -0,0 +1,82 @@
1
+ require "bento/common"
2
+
3
+ class NormalizeRunner
4
+ include Common
5
+ include PackerExec
6
+
7
+ attr_reader :templates, :build_timestamp, :debug, :override_version
8
+
9
+ def initialize(opts)
10
+ @templates = opts.template_files
11
+ @debug = opts.debug
12
+ @modified = []
13
+ @build_timestamp = Time.now.gmtime.strftime("%Y%m%d%H%M%S")
14
+ end
15
+
16
+ def start
17
+ banner("Normalizing for templates:")
18
+ templates.each { |t| puts "- #{t}" }
19
+ time = Benchmark.measure do
20
+ templates.each do |file|
21
+ dir, template = file.split("/")[0], file.split("/")[1]
22
+ Dir.chdir dir
23
+ validate(template)
24
+ Dir.chdir("..")
25
+ end
26
+ end
27
+ if !@modified.empty?
28
+ info("")
29
+ info("The following templates were modified:")
30
+ @modified.sort.each { |template| info(" * #{template}") }
31
+ end
32
+ banner("Normalizing finished in #{duration(time.real)}.")
33
+ end
34
+
35
+ private
36
+
37
+ def checksum(file)
38
+ Digest::MD5.file(file).hexdigest
39
+ end
40
+
41
+ def fix(template)
42
+ file = "#{template}.json"
43
+
44
+ banner("[#{template}] Fixing")
45
+ original_checksum = checksum(file)
46
+ output = `packer fix #{file}`
47
+ raise "[#{template}] Error fixing, exited #{$?}" if $?.exitstatus != 0
48
+ # preserve ampersands in shell commands,
49
+ # see: https://github.com/mitchellh/packer/issues/784
50
+ output.gsub!("\\u0026", "&")
51
+ File.open(file, "wb") { |dest| dest.write(output) }
52
+ fixed_checksum = checksum(file)
53
+
54
+ if original_checksum == fixed_checksum
55
+ puts("No changes made.")
56
+ else
57
+ warn("Template #{template} has been modified.")
58
+ @modified << template
59
+ end
60
+ end
61
+
62
+ def packer_validate_cmd(template, var_file)
63
+ vars = "#{template}.variables.json"
64
+ cmd = %W{packer validate -var-file=#{var_file} #{template}.json}
65
+ cmd.insert(2, "-var-file=#{vars}") if File.exist?(vars)
66
+ cmd
67
+ end
68
+
69
+ def validate(template)
70
+ for_packer_run_with(template) do |md_file, var_file|
71
+ cmd = packer_validate_cmd(template, var_file.path)
72
+ banner("[#{template}] Validating: '#{cmd.join(' ')}'")
73
+ if debug
74
+ banner("[#{template}] DEBUG: var_file(#{var_file.path}) is:")
75
+ puts IO.read(var_file.path)
76
+ banner("[#{template}] DEBUG: md_file(#{md_file.path}) is:")
77
+ puts IO.read(md_file.path)
78
+ end
79
+ system(*cmd) || raise( "[#{template}] Error validating, exited #{$?}")
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,31 @@
1
+
2
+ module PackerExec
3
+ def for_packer_run_with(template)
4
+ Tempfile.open("#{template}-metadata.json") do |md_file|
5
+ Tempfile.open("#{template}-metadata-var-file") do |var_file|
6
+ write_box_metadata(template, md_file)
7
+ write_var_file(template, md_file, var_file)
8
+ yield md_file, var_file
9
+ end
10
+ end
11
+ end
12
+
13
+ def write_box_metadata(template, io)
14
+ md = BuildMetadata.new(template, build_timestamp, override_version).read
15
+ io.write(JSON.pretty_generate(md))
16
+ io.close
17
+ end
18
+
19
+ def write_var_file(template, md_file, io)
20
+ md = BuildMetadata.new(template, build_timestamp, override_version).read
21
+
22
+ io.write(JSON.pretty_generate({
23
+ box_basename: md[:box_basename],
24
+ build_timestamp: md[:build_timestamp],
25
+ git_revision: md[:git_revision],
26
+ metadata: md_file.path,
27
+ version: md[:version],
28
+ }))
29
+ io.close
30
+ end
31
+ end
@@ -0,0 +1,84 @@
1
+ require "digest"
2
+ require "bento/common"
3
+
4
+ class ProviderMetadata
5
+ include Common
6
+
7
+ def initialize(path, box_basename)
8
+ @base = File.join(path, box_basename)
9
+ end
10
+
11
+ def read
12
+ Dir.glob("#{base}.*.box").map do |file|
13
+ {
14
+ name: provider_from_file(file),
15
+ version: version(provider_from_file(file)),
16
+ file: "#{File.basename(file)}",
17
+ checksum_type: "sha256",
18
+ checksum: shasum(file),
19
+ size: "#{size_in_mb(file)} MB",
20
+ }
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :base
27
+
28
+ def provider_from_file(file)
29
+ provider = file.sub(/^.*\.([^.]+)\.box$/, '\1')
30
+ if provider == "vmware"
31
+ "vmware_desktop"
32
+ else
33
+ provider
34
+ end
35
+ end
36
+
37
+ def shasum(file)
38
+ Digest::SHA256.file(file).hexdigest
39
+ end
40
+
41
+ def size_in_mb(file)
42
+ size = File.size(file)
43
+ size_mb = size / MEGABYTE
44
+ size_mb.ceil.to_s
45
+ end
46
+
47
+ def version(provider)
48
+ case provider
49
+ when /vmware/
50
+ ver_vmware
51
+ when /virtualbox/
52
+ ver_vbox
53
+ when /parallels/
54
+ ver_parallels
55
+ end
56
+ end
57
+
58
+ def ver_vmware
59
+ if os_x?
60
+ path = File.join('/Applications/VMware\ Fusion.app/Contents/Library')
61
+ fusion_cmd = File.join(path, "vmware-vmx -v")
62
+ cmd = Mixlib::ShellOut.new(fusion_cmd)
63
+ cmd.run_command
64
+ cmd.stderr.split(" ")[5]
65
+ else
66
+ cmd = Mixlib::ShellOut.new("vmware --version")
67
+ cmd.run_command
68
+ cmd.stdout.split(" ")[2]
69
+ end
70
+ end
71
+
72
+ def ver_parallels
73
+ raise "Platform is not macOS / OS X, exiting..." unless os_x?
74
+ cmd = Mixlib::ShellOut.new("prlctl --version")
75
+ cmd.run_command
76
+ cmd.stdout.split(" ")[2]
77
+ end
78
+
79
+ def ver_vbox
80
+ cmd = Mixlib::ShellOut.new("VBoxManage --version")
81
+ cmd.run_command
82
+ cmd.stdout.split("r")[0]
83
+ end
84
+ end
@@ -0,0 +1,22 @@
1
+ require "bento/common"
2
+
3
+ class ReleaseRunner
4
+ include Common
5
+
6
+ attr_reader :box, :version
7
+
8
+ def initialize(opts)
9
+ @box = opts.box
10
+ @version = opts.version
11
+ end
12
+
13
+ def start
14
+ banner("Releasing #{box}/#{version}...")
15
+ time = Benchmark.measure do
16
+ b = vc_account.get_box(box)
17
+ v = b.get_version(version)
18
+ v.release
19
+ end
20
+ banner("Release finished in #{duration(time.real)}.")
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require "bento/common"
2
+
3
+ class RevokeRunner
4
+ include Common
5
+
6
+ attr_reader :box, :version
7
+
8
+ def initialize(opts)
9
+ @box = opts.box
10
+ @version = opts.version
11
+ end
12
+
13
+ def start
14
+ banner("Revoking #{box}/#{version}...")
15
+ time = Benchmark.measure do
16
+ box = vc_account.get_box(box)
17
+ version = box.get_version(version)
18
+ version.revoke
19
+ end
20
+ banner("Revoke finished in #{duration(time.real)}.")
21
+ end
22
+ end
data/lib/bento/test.rb ADDED
@@ -0,0 +1,60 @@
1
+ require "bento/common"
2
+ require "mixlib/shellout"
3
+ require "erb"
4
+
5
+ class TestRunner
6
+ include Common
7
+
8
+ attr_reader :shared_folder, :boxname, :provider, :box_url, :no_shared, :provisioner
9
+
10
+ def initialize(opts)
11
+ @debug = opts.debug
12
+ @no_shared = opts.no_shared
13
+ @provisioner = opts.provisioner.nil? ? "shell" : opts.provisioner
14
+ end
15
+
16
+ def start
17
+ banner("Starting testing...")
18
+ time = Benchmark.measure do
19
+ metadata_files.each do |metadata_file|
20
+ destroy_all_bento
21
+ test_box(metadata_file)
22
+ destroy_all_bento
23
+ end
24
+ end
25
+ banner("Testing finished in #{duration(time.real)}.")
26
+ end
27
+
28
+ private
29
+
30
+ def destroy_all_bento
31
+ cmd = Mixlib::ShellOut.new("vagrant box list | grep 'bento-'")
32
+ cmd.run_command
33
+ boxes = cmd.stdout.split("\n")
34
+
35
+ boxes.each do |box|
36
+ b = box.split(" ")
37
+ rm_cmd = Mixlib::ShellOut.new("vagrant box remove --force #{b[0]} --provider #{b[1].to_s.gsub(/(,|\()/, '')}")
38
+ banner("Removing #{b[0]} for provider #{b[1].to_s.gsub(/(,|\()/, '')}")
39
+ rm_cmd.run_command
40
+ end
41
+ end
42
+
43
+ def test_box(md_json)
44
+ md = box_metadata(md_json)
45
+ @boxname = md["name"]
46
+ @providers = md["providers"]
47
+ @share_disabled = no_shared || /(bsd|opensuse)/.match(boxname) ? true : false
48
+
49
+ dir = "#{File.expand_path("../../", File.dirname(__FILE__))}/templates"
50
+ %w{.kitchen.yml bootstrap.sh}.each do |file|
51
+ t = file =~ /kitchen/ ? "kitchen.yml.erb" : "#{file}.erb"
52
+ erb = ERB.new(File.read(dir + "/#{t}"), nil, "-").result(binding)
53
+ File.open(file, "w") { |f| f.puts erb }
54
+ end
55
+
56
+ test = Mixlib::ShellOut.new("kitchen test", :timeout => 900, live_stream: STDOUT)
57
+ test.run_command
58
+ test.error!
59
+ end
60
+ end
@@ -0,0 +1,47 @@
1
+ require "bento/common"
2
+
3
+ class UploadRunner
4
+ include Common
5
+
6
+ attr_reader :md_json
7
+
8
+ def initialize(opts)
9
+ @md_json = opts.md_json
10
+ end
11
+
12
+ def start
13
+ banner("Starting uploads...")
14
+ time = Benchmark.measure do
15
+ files = md_json ? [md_json] : metadata_files
16
+ files.each do |md_file|
17
+ upload(md_file)
18
+ end
19
+ end
20
+ banner("Uploads finished in #{duration(time.real)}.")
21
+ end
22
+
23
+ def upload(md_file)
24
+ md = box_metadata(md_file)
25
+ box_desc = "a bento box for #{md['name']}"
26
+ box = vc_account.ensure_box(md["name"], box_desc, private_box?(md["name"]))
27
+ box_ver = box.ensure_version(md["version"], File.read(md_file))
28
+
29
+ if builds_yml["slugs"].values.include?(box.name)
30
+ slug_desc = "a bento box for #{builds_yml['slugs'].key(box.name)}"
31
+ slug = vc_account.ensure_box(builds_yml["slugs"].key(box.name), slug_desc, false)
32
+ slug_ver = slug.ensure_version(md["version"], File.read(md_file))
33
+ end
34
+
35
+ md["providers"].each do |k, v|
36
+ provider = box_ver.ensure_provider(k, nil)
37
+ banner("Uploading #{box.name}/#{box_ver.version}/#{provider.name}...")
38
+ provider.upload_file("builds/#{v['file']}")
39
+ banner("#{provider.download_url}")
40
+ next unless builds_yml["slugs"].values.include?(box.name)
41
+ slug_provider = slug_ver.ensure_provider(k, nil)
42
+ banner("Uploading #{slug.name}/#{slug_ver.version}/#{slug_provider.name}...")
43
+ slug_provider.upload_file("builds/#{v['file']}")
44
+ banner("#{slug_provider.download_url}")
45
+ end
46
+ end
47
+ end