vagrant-packer-plugin 0.8.0

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9edb2c3ae76e73c18b9e4e9ae8441f1a6d081009
4
+ data.tar.gz: 302fcabf688888a6b60ed7d98d064587478cd6a3
5
+ SHA512:
6
+ metadata.gz: 0087a22b554eba6191daa03addcd3b3cb8d0ac3c3f7d3284386ace0a271ed88b5a7804c2cdffd3af5787879607b3e8c0b64cfd1500bdde2e3fa8d58a533be71a
7
+ data.tar.gz: 38fa0e9e98248ec3ecbc9b3337ab0becd4f2a2c754b5954b09715b994e9a3d9554c32daa42ff1b793ff2f97e2da06e46920b2ff578c10a868f48e59e82d7847d
@@ -0,0 +1,20 @@
1
+ **/alf_data_shared
2
+ **/maven_repos/private.json
3
+ *.lock
4
+ dev/Berksfile.dev
5
+ .vagrant
6
+ *.box
7
+ Gemfile.lock
8
+ vendor-cookbooks
9
+ packer_cache
10
+ output-virtualbox-iso
11
+ *.lic
12
+ *.tar
13
+ bootstrap-data
14
+ license
15
+
16
+ # Ignore Packer builders
17
+ *-builder.json
18
+
19
+ # Ignore gem builds
20
+ # pkg
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem "vagrant", git: "https://github.com/mitchellh/vagrant.git"
7
+ end
8
+
9
+ group :plugins do
10
+ gem "vagrant-packer-plugin", path: "."
11
+ end
@@ -0,0 +1,30 @@
1
+ # Vagrant Packer plugin
2
+
3
+ ## What Is
4
+ Vagrant Packer plugin allows to compose Packer templates and run them using vagrant and `Vagrantfile`; it also helps using Chef as provisioner.
5
+
6
+ ## Install
7
+ - Install [Vagrant](https://www.vagrantup.com/downloads.html)
8
+ - Install [Packer (0.8.6+)](https://www.packer.io/downloads.html)
9
+ - Install Vagrant Packer plugin
10
+ ```
11
+ curl -L --no-sessionid https://github.com/Alfresco/vagrant-packer-plugin/blob/master/pkg/vagrant-packer-plugin-0.5.0.gem > ~/.vagrant.d/vagrant-packer-plugin-0.5.0.gem
12
+ vagrant plugin install ~/.vagrant.d/vagrant-packer-plugin-0.5.0.gem
13
+ ```
14
+
15
+ ## Use
16
+ Define the following `Vagrantfile` and run `vagrant up` from the same folder
17
+ ```
18
+ Vagrant.configure("2") do |config|
19
+ config.packer_build.instance_templates = ["instance1.json","instance2.json"]
20
+ config.packer_build.ks_template = "https://raw.githubusercontent.com/Alfresco/alfresco-spk/master/ks/ks-centos.cfg"
21
+ end
22
+ ```
23
+
24
+ Type `vagrant packer-build -h` for more info on configuration.
25
+
26
+ ## Local testing
27
+ Build Vagrant Packer plugin locally
28
+ ```
29
+ rm Gemfile.lock ; bundle ; rake build ; vagrant plugin install pkg/vagrant-packer-plugin-0.5.0.gem
30
+ ```
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "allinone-community",
3
+ "nginx" : {
4
+ "use_nossl_config" : true,
5
+ "disable_nginx_init" : true
6
+ },
7
+ "alfresco" : {
8
+ "skip_certificate_creation" : true,
9
+ "public_protocol" : "http",
10
+ "public_portssl" : "80"
11
+ },
12
+ "run_list": ["alfresco::default"]
13
+ }
@@ -0,0 +1,82 @@
1
+ # Copied from https://github.com/chef/bento/blob/master/http/centos-7.1/ks.cfg
2
+
3
+ install
4
+ cdrom
5
+ lang en_US.UTF-8
6
+ keyboard us
7
+ network --bootproto=dhcp
8
+ rootpw vagrant
9
+ firewall --disabled
10
+ selinux --permissive
11
+ timezone UTC
12
+ unsupported_hardware
13
+ bootloader --location=mbr
14
+ text
15
+ skipx
16
+ zerombr
17
+ clearpart --all --initlabel
18
+ autopart
19
+ auth --enableshadow --passalgo=sha512 --kickstart
20
+ firstboot --disabled
21
+ reboot
22
+ user --name=vagrant --plaintext --password vagrant
23
+
24
+ %packages --nobase --ignoremissing --excludedocs
25
+ # vagrant needs this to copy initial files via scp
26
+ openssh-clients
27
+ sudo
28
+ kernel-headers
29
+ kernel-devel
30
+ gcc
31
+ make
32
+ perl
33
+ wget
34
+ nfs-utils
35
+ net-tools
36
+ bzip2
37
+ -fprintd-pam
38
+ -intltool
39
+
40
+ # unnecessary firmware
41
+ -aic94xx-firmware
42
+ -atmel-firmware
43
+ -b43-openfwwf
44
+ -bfa-firmware
45
+ -ipw2100-firmware
46
+ -ipw2200-firmware
47
+ -ivtv-firmware
48
+ -iwl100-firmware
49
+ -iwl105-firmware
50
+ -iwl135-firmware
51
+ -iwl1000-firmware
52
+ -iwl2000-firmware
53
+ -iwl2030-firmware
54
+ -iwl3160-firmware
55
+ -iwl3945-firmware
56
+ -iwl4965-firmware
57
+ -iwl5000-firmware
58
+ -iwl5150-firmware
59
+ -iwl6000-firmware
60
+ -iwl6000g2a-firmware
61
+ -iwl6000g2b-firmware
62
+ -iwl6050-firmware
63
+ -iwl7260-firmware
64
+ -libertas-usb8388-firmware
65
+ -libertas-sd8686-firmware
66
+ -libertas-sd8787-firmware
67
+ -ql2100-firmware
68
+ -ql2200-firmware
69
+ -ql23xx-firmware
70
+ -ql2400-firmware
71
+ -ql2500-firmware
72
+ -rt61pci-firmware
73
+ -rt73usb-firmware
74
+ -xorg-x11-drv-ati-firmware
75
+ -zd1211-firmware
76
+ %end
77
+
78
+ %post
79
+ # sudo
80
+ echo "%vagrant ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/vagrant
81
+ sed -i "s/^[^#].*requiretty/#Defaults requiretty/" /etc/sudoers
82
+ %end
@@ -0,0 +1,9 @@
1
+ {
2
+ "type": "chef-solo",
3
+ "execute_command" : "cd /tmp/packer-chef-solo && ln -s cookbooks-0 cookbooks && {{if .Sudo}}sudo {{end}}chef-client --no-color -z -j {{.JsonPath}}",
4
+ "install_command": "bash -c 'curl -L https://www.opscode.com/chef/install.sh| bash -s -- -v 12.5.1'",
5
+ "prevent_sudo": true,
6
+ "skip_install": false,
7
+ "cookbook_paths": ["./cookbooks"],
8
+ "run_list": ["alfresco::default"]
9
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "shell",
3
+ "inline": ["setenforce 0"]
4
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "type" : "vagrant",
3
+ "output" : "{{user `vagrant_output_file`}}",
4
+ "compression_level" : 7,
5
+ "keep_input_artifact" : true
6
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "alfresco-allinone" : {
3
+ "_images" : {
4
+ "provisioners" : {
5
+ "selinux-permissive" : "packer/selinux-permissive-provisioner.json",
6
+ "chef-alfresco" : "packer/chef-alfresco-provisioner.json"
7
+ },
8
+ "builders" : {
9
+ "virtualbox-ovf" : "packer/virtualbox-ovf-builder.json"
10
+ },
11
+ "postprocessors" : {
12
+ "vagrantbox" : "packer/vagrantbox-postprocessor.json"
13
+ },
14
+ "variables" : {
15
+ "vagrant_output_file" : "alfresco-community-5.1.c-ea-{{timestamp}}",
16
+ "iso_url" : "http://mirror.amsiohosting.net/centos.org/7.2.1511/isos/x86_64/CentOS-7-x86_64-Minimal-1511.iso",
17
+ "iso_checksum" : "f90e4d28fa377669b2db16cbcb451fcb9a89d2460e3645993e30e137ac37d284",
18
+ "iso_checksum_type" : "sha256",
19
+ "ssh_username" : "root",
20
+ "ssh_password" : "vagrant",
21
+ "ks_path" : "ks.cfg",
22
+ "http_directory" : "../",
23
+ "guest_os_type" : "RedHat_64",
24
+ "headless" : "false",
25
+ "output_directory": "vbox-output",
26
+ "vm_name": "alfresco-community-5.1.c-ea-{{timestamp}}",
27
+ "ami_description" : "Alfresco Community 5.1.c-EA - Allinone Server - {{timestamp}}",
28
+ "ami_name" : "Alfresco Community 5.1.c-EA - Allinone Server - {{timestamp}}"
29
+ }
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+
3
+ begin
4
+ require 'vagrant'
5
+ rescue LoadError
6
+ Bundler.require(:default, :development)
7
+ end
8
+
9
+ require 'vagrant-packer-plugin/plugin'
10
+ require 'vagrant-packer-plugin/command'
@@ -0,0 +1,125 @@
1
+ require_relative 'config'
2
+
3
+ require 'vagrant-packer-plugin/utils/downloader'
4
+ require 'vagrant-packer-plugin/commons/engine'
5
+ require 'vagrant-packer-plugin/support/packer_build_images'
6
+ require 'vagrant-packer-plugin/support/packer_commands'
7
+
8
+ require 'berkshelf'
9
+ require 'optparse'
10
+ require 'fileutils'
11
+ module VagrantPlugins
12
+ module PackerBuild
13
+ class Command < Vagrant.plugin('2', :command)
14
+
15
+ def initialize(args, env)
16
+ @params = VagrantPlugins::PackerBuild::Config.new
17
+ if env.vagrantfile.config.packer_build.is_a?(VagrantPlugins::PackerBuild::Config)
18
+ @params = env.vagrantfile.config.packer_build
19
+ end
20
+ end
21
+
22
+ def self.synopsis
23
+ 'Build immutable images using Packer'
24
+ end
25
+
26
+ def execute
27
+ OptionParser.new do |opts|
28
+ opts.banner = "Usage: vagrant packer-build "\
29
+ "[-b|--box-url] "\
30
+ "[-n|--box-name] "\
31
+ "[-c|--cookbooks-url] "\
32
+ "[-d|--databags-url] "\
33
+ "[-k|--ks-template] "\
34
+ "[-B|--berksfile] "\
35
+ "[-i|--instance-templates] "\
36
+ "[-D|--packer-debug] "\
37
+ "[-w|--why-run] "
38
+
39
+ opts.separator ""
40
+
41
+ opts.on("-b", "--box-url [URL]", String, "Url of the template box for the virtual machine") do |box_url|
42
+ @params.box_url = box_url
43
+ end
44
+
45
+ opts.on("-n", "--box-name [NAME]", String, "Name of the stack virtual machines") do |box_name|
46
+ @params.box_name = box_name
47
+ end
48
+
49
+ opts.on("-c", "--cookbooks-url [URL]", String, "URL resolving Berkshelf (Cookbook repo) tar.gz archive") do |cookbooks_url|
50
+ @params.cookbooks_url = cookbooks_url
51
+ end
52
+
53
+ opts.on("-d", "--databags-url [URL]", String, "URL resolving Chef databags tar.gz archive") do |databags_url|
54
+ @params.databags_url = databags_url
55
+ end
56
+
57
+ opts.on("-k", "--ks-template [PATH]", String, "URL resolving the ks template for the machine (only used by Vagrant Box Image building)") do |ks_template|
58
+ @params.ks_template = ks_template
59
+ end
60
+
61
+ opts.on("-B", "--berksfile [PATH]", String, "path resolving the Berksfile)") do |berksfile|
62
+ @params.berksfile = berksfile
63
+ end
64
+
65
+ opts.on("-i", "--instance-templates [PATH1],[PATH2]", String, "URL resolving the instance templates") do |instance_templates|
66
+ @params.instance_templates = instance_templates
67
+ end
68
+
69
+ opts.on("-D", "--packer-debug", "true, to run packer in debug mode; default is false") do |debug|
70
+ @params.debug = debug
71
+ end
72
+
73
+ opts.on("-w", "--why-run", "Why run mode will just test configuration but will not run or build anything") do |why_run|
74
+ @params.why_run = why_run
75
+ end
76
+ end.parse!
77
+
78
+ @params.finalize!
79
+
80
+ # this code will be run only if the command wasn't asking for helpls
81
+ @engine = VagrantPlugins::PackerBuild::Commons::Engine.new
82
+ @engine.create_work_dir(@params.work_dir)
83
+
84
+ if @params.ks_template
85
+ Downloader.get(@params.ks_template, "#{@params.work_dir}/ks.cfg" )
86
+ end
87
+
88
+ # Invoke Berkshelf, if Berksfile is configured
89
+ if @params.berksfile
90
+ @engine.invoke_berkshelf(@params.work_dir, "cookbooks")
91
+ end
92
+
93
+ # Download Chef cookbooks via URL or path
94
+ if @params.cookbooks_url
95
+ @engine.get_artifact(@params.work_dir, @params.cookbooks_url, "cookbooks")
96
+ end
97
+
98
+ # Download Chef databags via URL or path
99
+ if @params.databags_url
100
+ @engine.get_artifact(@params.work_dir, @params.databags_url, "databags", @params)
101
+ end
102
+
103
+ # TODO - why saving attributes in single files if we have the instance-template nodes that have it all?
104
+ # if @params.berksfile || @params.cookbooks_url
105
+ # chef_items = @engine.get_chef_items(nodes, @params.work_dir, @params.cookbooks_url, @params.databags_url)
106
+ # end
107
+
108
+ if !@params.why_run
109
+ nodes = @engine.get_instance_templates(@params.work_dir, @params.instance_templates)
110
+ PackerBuildImages.new(@params, @engine, nodes).execute!
111
+ else
112
+ abort("Why run mode selected - not continuing")
113
+ end
114
+ end
115
+
116
+ def validate
117
+ errors = ""
118
+ if @params.instance_templates.nil? or @params.instance_templates.empty?
119
+ errors << "You must provide at least one instance template"
120
+ end
121
+ errors
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,93 @@
1
+ require 'vagrant-packer-plugin/utils/downloader'
2
+ require 'vagrant-packer-plugin/utils/unpacker'
3
+ require 'json/merge_patch'
4
+ require 'fileutils'
5
+ require 'json'
6
+ require 'yaml'
7
+ require 'open3'
8
+ require 'pry'
9
+
10
+ module VagrantPlugins
11
+ module PackerBuild
12
+ module Commons
13
+ class Engine
14
+
15
+ def fetch_cookbook_version
16
+ result = ""
17
+ begin
18
+ result = open("#{Dir.pwd}/metadata.rb").grep(/version/).first.split(" ").last.gsub(/\"/,'')
19
+ rescue
20
+ end
21
+ result
22
+ end
23
+
24
+
25
+ def create_work_dir(work_dir)
26
+ FileUtils.mkdir_p("#{work_dir}")
27
+ puts "[packer-info] Created #{work_dir} folder\n"
28
+ end
29
+
30
+
31
+ def get_instance_templates(work_dir, instance_templates)
32
+ json_ret = {}
33
+ instance_templates.each_with_index do |instance_template,index|
34
+ node_name = JSON.parse(File.read(instance_template))['name']
35
+ json_ret[instance_template] = get_json(work_dir, "attributes-#{node_name}.json", instance_template)
36
+ end
37
+ return json_ret
38
+ end
39
+
40
+ def get_json(work_dir, file_name, url)
41
+ Downloader.get(url, "#{work_dir}/#{file_name}")
42
+ return JSON.parse(File.read("#{work_dir}/#{file_name}"))
43
+ end
44
+
45
+ # Not needed anymore
46
+ # def get_chef_items(nodes, work_dir, cookbooks_url, databags_url)
47
+ # nodes.each do |filename,node|
48
+ # node['_local'] = {}
49
+ #
50
+ # attr_file = File.open("#{work_dir}/attributes-#{node['name']}.json", 'w')
51
+ # attr_file.write(node.to_json)
52
+ # attr_file.close()
53
+ # end
54
+ # end
55
+
56
+ def get_node_attrs(work_dir, chef_node_name)
57
+ box_attrs = File.read("#{work_dir}/attributes-#{chef_node_name}.json")
58
+ return JSON.parse(box_attrs)
59
+ end
60
+
61
+ def invoke_berkshelf(work_dir, path_name)
62
+ puts "[packer-info] Trying to delete Berksfile.lock"
63
+ begin
64
+ File.delete("#{Dir.pwd}/Berksfile.lock")
65
+ puts "[packer-info] local Berksfile.lock removed!"
66
+ rescue Errno::ENOENT
67
+ puts "[packer-info] File not found, continuing normally.."
68
+ end
69
+
70
+ puts "[packer-info] Packaging Chef Cookbooks repo with berks vendor..."
71
+ Berkshelf::Cli.start(["vendor","#{work_dir}/#{path_name}"])
72
+ # TODO - consider also params.berksfile, but not working yet
73
+ # Berkshelf::Cli.start(["package",@params.cookbooks_url.split('/')[-1],"-b #{@params.berksfile}"])
74
+ end
75
+
76
+ def get_artifact(work_dir, url, artifact_name, params=nil)
77
+ # Download and uncompress Chef artifacts (in a Berkshelf package format)
78
+ if url and url.length != 0
79
+ Downloader.get(url, "#{work_dir}/#{artifact_name}.tar.gz",params)
80
+ FileUtils.rm_rf("#{work_dir}/#{artifact_name}")
81
+ Unpacker.tar("#{artifact_name}.tar.gz", work_dir)
82
+ print "Unpacked #{work_dir}/#{artifact_name}.tar.gz into #{work_dir}\n"
83
+ end
84
+ end
85
+
86
+ def yaml_to_json(yaml)
87
+ data = YAML::load(yaml)
88
+ return JSON.dump(data)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,32 @@
1
+
2
+ module VagrantPlugins
3
+ module PackerBuild
4
+ class Config < Vagrant.plugin(2, :config)
5
+ attr_accessor :work_dir, :debug, :box_url, :box_name, :cookbooks_url, :databags_url, :databags_username, :databags_password, :instance_templates, :pre_commands, :post_commands, :env_vars, :ks_template, :berksfile, :why_run
6
+
7
+ def initialize
8
+ @work_dir = UNSET_VALUE
9
+ @box_url = UNSET_VALUE
10
+ @box_name = UNSET_VALUE
11
+ @cookbooks_url = UNSET_VALUE
12
+ @databags_url = UNSET_VALUE
13
+ @databags_username = UNSET_VALUE
14
+ @databags_password = UNSET_VALUE
15
+ @ks_template = UNSET_VALUE
16
+ @berksfile = UNSET_VALUE
17
+ end
18
+
19
+ def finalize!
20
+ @work_dir = "#{Dir.home}/.vagrant.d/data/packer-plugin" if @work_dir == UNSET_VALUE
21
+ @box_url = 'http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-7.2_chef-provisionerless.box' if @box_url == UNSET_VALUE
22
+ @box_name = "opscode_centos-7.2" if @box_name == UNSET_VALUE
23
+ @cookbooks_url = nil if @cookbooks_url == UNSET_VALUE
24
+ @databags_url = nil if @databags_url == UNSET_VALUE
25
+ @databags_username = nil if @databags_username == UNSET_VALUE
26
+ @databags_password = nil if @databags_password == UNSET_VALUE
27
+ @ks_template = "" if @ks_template == UNSET_VALUE
28
+ @berksfile = nil if @berksfile == UNSET_VALUE
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+
2
+
3
+ module Packer
4
+ class DataObject
5
+ def __add_array_of_strings(key, values, exclusives = [])
6
+ self.__exclusive_key_error(key, exclusives)
7
+ if Array.try_convert(values)
8
+ #adding var as array of string - #{key.to_s}=#{values.to_ary.map(&:to_s)}
9
+ self.data[key.to_s] = values.to_ary.map(&:to_s)
10
+ else
11
+ #adding var as string - #{key.to_s}=#{values}"
12
+ self.data[key.to_s] = values
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+ require 'vagrant-packer-plugin/patches/dataobject'
2
+ require 'open3'
3
+ require 'shellwords'
4
+
5
+ module Packer
6
+ class Runner
7
+ class CommandExecutionError < StandardError
8
+ end
9
+
10
+ def self.run!(*args, quiet: false)
11
+ cmd = Shellwords.shelljoin(args.flatten)
12
+
13
+ debug = cmd.include? '-debug'
14
+
15
+ status = 0
16
+ stdout = ''
17
+ stderr = ''
18
+ if quiet && !debug
19
+ # Run without streaming std* to any screen
20
+ stdout, stderr, status = Open3.capture3(cmd)
21
+ else
22
+ # Run but stream as well as capture stdout to the screen
23
+ # see: http://stackoverflow.com/a/1162850/83386
24
+ Open3.popen3(cmd) do |std_in, std_out, std_err, thread|
25
+ # read each stream from a new thread
26
+ Thread.new do
27
+ until (raw = std_out.getc).nil? do
28
+ stdout << raw
29
+ $stdout.write "#{raw}"
30
+ end
31
+ end
32
+ Thread.new do
33
+ until (raw_line = std_err.gets).nil? do
34
+ stderr << raw_line
35
+ end
36
+ end
37
+
38
+ Thread.new do
39
+ std_in.puts $stdin.gets while thread.alive?
40
+ end
41
+
42
+ thread.join # don't exit until the external process is done
43
+ status = thread.value
44
+ end
45
+ end
46
+ raise CommandExecutionError.new(stderr) unless status == 0
47
+ stdout
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ module VagrantPlugins
2
+ module PackerBuild
3
+ class Plugin < Vagrant.plugin('2')
4
+ name "vagrant-packer-plugin"
5
+
6
+ description <<-DESC
7
+
8
+ DESC
9
+
10
+ config 'packer_build' do
11
+ require_relative 'config'
12
+ Config
13
+ end
14
+
15
+ command 'packer-build' do
16
+ require_relative 'command'
17
+ Command
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ require 'vagrant-packer-plugin/utils/packer_interface'
2
+
3
+ class PackerBuildImages
4
+ def initialize(params, engine, chef_items)
5
+ @params = params
6
+ @chef_items = chef_items
7
+ @engine = engine
8
+ end
9
+
10
+ def execute!
11
+ packer = PackerInterface.new(@params, @engine)
12
+ packer_defs = packer.get_defs(@chef_items)
13
+ packer.run_defs(packer_defs)
14
+ puts "Images built! Bye for now."
15
+ end
16
+ end
@@ -0,0 +1,44 @@
1
+ class PackerCommands
2
+
3
+ def initialize(params, engine, file_list, env_vars, mode)
4
+ @params = params
5
+ @engine = engine
6
+ @file_list = file_list
7
+ @env_vars = env_vars
8
+ @mode = mode
9
+ end
10
+
11
+ def execute!
12
+ validate
13
+ commands_final = []
14
+ @file_list.each { |file| commands_final << @engine.get_json(@params.work_dir, file.split('/')[-1], file) }
15
+
16
+ command_sh = @env_vars
17
+ commands_final.each do |commands|
18
+ commands.each do |command|
19
+ puts "[packer-#{@mode}] #{command[0]}"
20
+ puts "[packer-#{@mode}] DEBUG: #{command[1]}"
21
+ command_sh += command[1] + "\n"
22
+ end
23
+ end
24
+ command_file = "/tmp/#{@mode}-commands.sh"
25
+ File.open(command_file, 'w') { |file| file.write(command_sh) }
26
+ FileUtils.chmod(0755, command_file);
27
+ stdout, stderr, status = Open3.capture3(command_file)
28
+ puts "[packer-#{@mode}] RET: #{status}, ERR: #{stderr}, OUT: #{stdout}"
29
+ end
30
+
31
+ private
32
+
33
+ def validate
34
+ print @engine
35
+
36
+ raise ArgumentError.new("Params should be an instance of VagrantPlugins::PackerBuild::Config") if !@params.is_a?(VagrantPlugins::PackerBuild::Config)
37
+ raise ArgumentError.new("Engine should be an instance of VagrantPlugins::PackerBuild::Commons::Engine") if !@engine.is_a?(VagrantPlugins::PackerBuild::Commons::Engine)
38
+ # raise ArgumentError.new("File list needs to be an Array, and cannot be empty") if !@file_list.is_a?(Array) or @file_list.empty?
39
+ raise ArgumentError.new("Environment variables should be a string and cannot be empty") if !@env_vars.is_a?(String)
40
+ raise ArgumentError.new("Mode should be either pre or post") if !["pre","post"].include?(@mode)
41
+ end
42
+
43
+
44
+ end
@@ -0,0 +1,32 @@
1
+ require 'open-uri'
2
+ require 'openssl'
3
+
4
+ class Downloader
5
+ def self.get(file, destination, params=nil)
6
+ if params.nil? or params.databags_username.nil?
7
+ file = file.gsub("file://", "")
8
+ file_path = file.gsub("$PWD", "#{Dir.pwd}")
9
+ puts "[packer-build] #{file_path} to #{destination}"
10
+ open(file_path) {|f|
11
+ File.open(destination,"wb") do |file|
12
+ file.puts f.read
13
+ end
14
+ }
15
+ else
16
+ self.get_with_auth(file, destination, params.databags_username, params.databags_password)
17
+ end
18
+ end
19
+
20
+ def self.get_with_auth(file, destination,user, password)
21
+ puts "[packer-build] retrieving with authentication"
22
+ file = file.gsub("file://", "")
23
+ file_path = file.gsub("$PWD", "#{Dir.pwd}")
24
+ puts "[packer-build] #{file_path} to #{destination}"
25
+ open(file_path, :http_basic_authentication => [user, password], :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE) {|f|
26
+ File.open(destination,"wb") do |file|
27
+ file.puts f.read
28
+ end
29
+ }
30
+ end
31
+
32
+ end
@@ -0,0 +1,120 @@
1
+ require 'packer-config'
2
+ require 'json/merge_patch'
3
+ require 'vagrant-packer-plugin/patches/runner'
4
+ require 'vagrant-packer-plugin/patches/dataobject'
5
+ require 'vagrant-packer-plugin/utils/downloader'
6
+ require 'pry'
7
+
8
+ class PackerInterface
9
+ def initialize(params, engine)
10
+ @params = params
11
+ @engine = engine
12
+ end
13
+
14
+ def get_defs(nodes)
15
+ packer_defs = {}
16
+ nodes.each do |_node_name,node|
17
+ node_name = node['name']
18
+ pconfig = Packer::Config.new "#{@params.work_dir}/#{node_name}-packer.json"
19
+ pconfig.description "VirtualBox vagrant for #{node_name}"
20
+
21
+ # => Building the packer config object variables
22
+ node['_images']['variables'].each {|variable_name, value| pconfig.add_variable "#{variable_name}", "#{value}"}
23
+ # => Building the packer config components: Builders, Provisioners and PostProcessors
24
+ parametrize(pconfig, "Builder", parse_packer_elements(node, node_name, 'builder', 'builders'))
25
+ parametrize(pconfig, "Provisioner", parse_packer_elements(node, node_name, 'provisioner', 'provisioners'))
26
+ parametrize(pconfig, "PostProcessor", parse_packer_elements(node, node_name, 'postprocessor', 'postprocessors'))
27
+ ENV['COOKBOOK_VERSION'] = @engine.fetch_cookbook_version
28
+
29
+ pconfig.validate
30
+ packer_defs[node_name] = pconfig
31
+ end
32
+
33
+ return packer_defs
34
+ end
35
+
36
+ def run_defs(packer_defs)
37
+ # Summarise Packer suites and ask for confirmation before running it
38
+ print "[packer-info] Running the following Packer templates:\n"
39
+ packer_defs.each do |packer_definition, packer|
40
+ print "[packer-info] Building #{packer_definition}-packer.json\n"
41
+ packer.packer_options << "-debug" if @params.debug
42
+ packer.build
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ # packer_element can be 'provisioners' or 'builders'; it's used to parse JSON input structure
49
+ # packer_element_type can be 'provisioner' or 'builder'; it's used to name files
50
+ def parse_packer_elements(node, node_name, packer_element_type, packer_element)
51
+ urls = node['_images'][packer_element]
52
+ ret = "["
53
+ if urls
54
+ urls.each do |element_name,url|
55
+ packer_filename = "#{@params.work_dir}/#{element_name}-#{packer_element_type}.json"
56
+ Downloader.get(url, packer_filename)
57
+ element = File.read(packer_filename)
58
+ elementJson = JSON.parse(element)
59
+
60
+ # Inject Chef attributes JSON into the chef-solo provisioner
61
+ if elementJson['type'] == 'chef-solo'
62
+ element = inject_chef_attributes(node['name'], element_name, elementJson)
63
+ end
64
+ ret += element + ","
65
+ end
66
+ ret = ret[0..-2]
67
+ end
68
+ ret += "]"
69
+ return ret
70
+ end
71
+
72
+ def inject_chef_attributes(node_name, provisioner_name, json_provisioner)
73
+ node_url = "#{@params.work_dir}/attributes-#{node_name}.json"
74
+ node_url_content = File.read(node_url)
75
+ json_provisioner['json'] = JSON.parse(node_url_content)
76
+ json_provisioner['json']['_images'] = {} if json_provisioner['json']['_images']
77
+ return json_provisioner.to_json
78
+ end
79
+
80
+ def parametrize(packer, type, components)
81
+ JSON.parse(components).each do |component|
82
+ class_name = "Packer::#{type}::#{component['type'].upcase.gsub('-','_')}"
83
+ config = packer.send("add_#{type.downcase}", Object.const_get(class_name))
84
+
85
+ # Little bit difficult to understand without knowing what is the .send command in ruby
86
+ # Basically this iterate through the entire json object and add the variable to the packer config.
87
+ # Since the keys of the json object are the same name of the packer config method, i can call them iteratively
88
+ # For example config.send("output_file", "example.box") is equal to config.output_file "example.box"
89
+ component.each do |key, value|
90
+ config.send("#{key}", value) if key != "type"
91
+ end
92
+
93
+ if type == "Provisioner" and component['type'] == "chef-solo"
94
+ config.required = ["type"]
95
+
96
+ if packer.variables["run_list"]
97
+ config.run_list packer.variables["run_list"].split(",")
98
+ else
99
+ config.run_list component["json"]["run_list"]
100
+ end
101
+
102
+ if @params.databags_url
103
+ config.data_bags_path "#{@params.work_dir}/data_bags"
104
+ end
105
+
106
+ if @params.berksfile || @params.cookbooks_url
107
+ config.cookbook_paths ["#{@params.work_dir}/cookbooks"]
108
+ end
109
+ end
110
+
111
+ # => The current chef-solo provisioner has a bug in which will not start as it requires an empty array to start
112
+ # => this is a bug, and a pull request is on it's way to solve this problem
113
+
114
+ # => We don't specify a communicator, and packer-config require one. So if it's not required, we will use ssh
115
+ if type == "Builder"
116
+ config.communicator "ssh" if component["communicator"].nil?
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,37 @@
1
+ #This class manage unpacking formats
2
+ #Since the formats are many (and not only tar), this class is expected to be a good target for refactoring in metaprogramming
3
+ #End of this class should be something like Unpacker.send("#{format}", file)
4
+
5
+ require "rubygems/package"
6
+ require 'zlib'
7
+
8
+
9
+ class Unpacker
10
+ TAR_LONGLINK = '././@LongLink'
11
+ def self.tar(file, destination)
12
+ puts "[packer-build] unpacking #{file} to #{destination}"
13
+ Gem::Package::TarReader.new( Zlib::GzipReader.open "#{destination}/#{file}" ) do |tar|
14
+ dest = nil
15
+ tar.each do |entry|
16
+ if entry.full_name == TAR_LONGLINK
17
+ dest = File.join destination, entry.read.strip
18
+ next
19
+ end
20
+ dest ||= File.join destination, entry.full_name
21
+ if entry.directory?
22
+ File.delete dest if File.file? dest
23
+ FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
24
+ elsif entry.file?
25
+ FileUtils.rm_rf dest if File.directory? dest
26
+ File.open dest, "wb" do |f|
27
+ f.print entry.read
28
+ end
29
+ FileUtils.chmod entry.header.mode, dest, :verbose => false
30
+ elsif entry.header.typeflag == '2' #Symlink!
31
+ File.symlink entry.header.linkname, dest
32
+ end
33
+ dest = nil
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module VagrantPlugins
2
+ module PackerBuild
3
+ VERSION = '0.8.0'
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path('../lib/vagrant-packer-plugin/version', __FILE__)
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "vagrant-packer-plugin"
5
+ spec.version = VagrantPlugins::PackerBuild::VERSION
6
+ spec.authors = ["Enzo Rivello", "Maurizio Pillitu"]
7
+ spec.email = ["enzo.rivello@alfresco.com"]
8
+ spec.homepage = "https://github.com/alfresco/vagrant-packer-plugin"
9
+
10
+ spec.summary = %q{Write a short summary, because Rubygems requires one.}
11
+ spec.description = %q{Write a longer description or delete this line.}
12
+ spec.license = "MIT"
13
+
14
+ spec.add_runtime_dependency 'berkshelf', '~> 4.0.1'
15
+ spec.add_runtime_dependency 'json-merge_patch', '~> 1.1'
16
+ spec.add_runtime_dependency 'pry', '~> 0.10.3'
17
+ spec.add_runtime_dependency "packer-config", "~> 1.5.0"
18
+ spec.add_development_dependency "bundler", "~> 1.10"
19
+ spec.add_development_dependency "rake", "~> 10.0"
20
+ spec.add_development_dependency 'yard', '~> 0.8.7.6'
21
+ spec.add_development_dependency 'rspec', '~> 3.4'
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+
29
+ end
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vagrant-packer-plugin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ platform: ruby
6
+ authors:
7
+ - Enzo Rivello
8
+ - Maurizio Pillitu
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2016-03-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: berkshelf
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 4.0.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 4.0.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: json-merge_patch
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.1'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.1'
42
+ - !ruby/object:Gem::Dependency
43
+ name: pry
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 0.10.3
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 0.10.3
56
+ - !ruby/object:Gem::Dependency
57
+ name: packer-config
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 1.5.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.5.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: bundler
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.10'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '1.10'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rake
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '10.0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '10.0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: yard
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: 0.8.7.6
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: 0.8.7.6
112
+ - !ruby/object:Gem::Dependency
113
+ name: rspec
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '3.4'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '3.4'
126
+ description: Write a longer description or delete this line.
127
+ email:
128
+ - enzo.rivello@alfresco.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - Gemfile
135
+ - README.md
136
+ - Rakefile
137
+ - files/instance-templates/allinone-community.json
138
+ - files/ks/ks-centos.cfg
139
+ - files/packer/chef-alfresco-provisioner.json
140
+ - files/packer/selinux-permissive-provisioner.json
141
+ - files/packer/vagrantbox-postprocessor.json
142
+ - files/stack-templates/community-allinone.json
143
+ - lib/vagrant-packer-plugin.rb
144
+ - lib/vagrant-packer-plugin/command.rb
145
+ - lib/vagrant-packer-plugin/commons/engine.rb
146
+ - lib/vagrant-packer-plugin/config.rb
147
+ - lib/vagrant-packer-plugin/patches/dataobject.rb
148
+ - lib/vagrant-packer-plugin/patches/runner.rb
149
+ - lib/vagrant-packer-plugin/plugin.rb
150
+ - lib/vagrant-packer-plugin/support/packer_build_images.rb
151
+ - lib/vagrant-packer-plugin/support/packer_commands.rb
152
+ - lib/vagrant-packer-plugin/utils/downloader.rb
153
+ - lib/vagrant-packer-plugin/utils/packer_interface.rb
154
+ - lib/vagrant-packer-plugin/utils/unpacker.rb
155
+ - lib/vagrant-packer-plugin/version.rb
156
+ - pkg/vagrant-packer-plugin-0.5.0.gem
157
+ - spk.gemspec
158
+ homepage: https://github.com/alfresco/vagrant-packer-plugin
159
+ licenses:
160
+ - MIT
161
+ metadata: {}
162
+ post_install_message:
163
+ rdoc_options: []
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ requirements: []
177
+ rubyforge_project:
178
+ rubygems_version: 2.4.5.1
179
+ signing_key:
180
+ specification_version: 4
181
+ summary: Write a short summary, because Rubygems requires one.
182
+ test_files: []
183
+ has_rdoc: