vagrant-packer-plugin 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: