packer-config 0.0.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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.rubocop.yml +340 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +17 -0
  6. data/LICENSE +176 -0
  7. data/README.md +107 -0
  8. data/Rakefile +47 -0
  9. data/TODO.md +8 -0
  10. data/lib/packer-config.rb +181 -0
  11. data/lib/packer/builder.rb +65 -0
  12. data/lib/packer/builders/all.rb +17 -0
  13. data/lib/packer/builders/amazon.rb +214 -0
  14. data/lib/packer/builders/docker.rb +47 -0
  15. data/lib/packer/builders/virtualbox.rb +169 -0
  16. data/lib/packer/dataobject.rb +128 -0
  17. data/lib/packer/envvar.rb +27 -0
  18. data/lib/packer/macro.rb +28 -0
  19. data/lib/packer/postprocessor.rb +77 -0
  20. data/lib/packer/postprocessors/all.rb +16 -0
  21. data/lib/packer/postprocessors/docker.rb +35 -0
  22. data/lib/packer/postprocessors/vagrant.rb +47 -0
  23. data/lib/packer/provisioner.rb +86 -0
  24. data/lib/packer/provisioners/all.rb +16 -0
  25. data/lib/packer/provisioners/file.rb +36 -0
  26. data/lib/packer/provisioners/shell.rb +60 -0
  27. data/packer-config.gemspec +46 -0
  28. data/spec/integration/README.md +14 -0
  29. data/spec/integration/builds/.gitignore +4 -0
  30. data/spec/integration/centos_vagrant_spec.rb +76 -0
  31. data/spec/integration/packer_cache/.gitignore +4 -0
  32. data/spec/integration/scripts/chef.sh +199 -0
  33. data/spec/integration/scripts/cleanup.sh +17 -0
  34. data/spec/integration/scripts/fix-slow-dns.sh +13 -0
  35. data/spec/integration/scripts/hello.sh +3 -0
  36. data/spec/integration/scripts/kickstart/centos-6.5-ks.cfg +71 -0
  37. data/spec/integration/scripts/minimize.sh +9 -0
  38. data/spec/integration/scripts/sshd.sh +6 -0
  39. data/spec/integration/scripts/vagrant.sh +10 -0
  40. data/spec/integration/scripts/vmtools.sh +39 -0
  41. data/spec/packer/builder_spec.rb +39 -0
  42. data/spec/packer/builders/amazon_spec.rb +88 -0
  43. data/spec/packer/builders/docker_spec.rb +25 -0
  44. data/spec/packer/builders/virtualbox_spec.rb +44 -0
  45. data/spec/packer/dataobject_spec.rb +239 -0
  46. data/spec/packer/envvar_spec.rb +38 -0
  47. data/spec/packer/macro_spec.rb +38 -0
  48. data/spec/packer/postprocessor_spec.rb +72 -0
  49. data/spec/packer/postprocessors/docker_import_spec.rb +27 -0
  50. data/spec/packer/postprocessors/docker_push_spec.rb +27 -0
  51. data/spec/packer/postprocessors/vagrant_spec.rb +27 -0
  52. data/spec/packer/provisioner_spec.rb +78 -0
  53. data/spec/packer/provisioners/file_spec.rb +63 -0
  54. data/spec/packer/provisioners/shell_spec.rb +116 -0
  55. data/spec/packer_config_spec.rb +197 -0
  56. data/spec/spec_helper.rb +19 -0
  57. data/spec/unit_helper.rb +15 -0
  58. metadata +220 -0
@@ -0,0 +1,47 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2014 Ian Chesal
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ require 'packer/builder'
16
+ require 'packer/dataobject'
17
+
18
+ module Packer
19
+ class Builder < Packer::DataObject
20
+ class Docker < Builder
21
+ def initialize
22
+ super
23
+ self.data['type'] = DOCKER
24
+ self.add_required(
25
+ 'export_path',
26
+ 'image'
27
+ )
28
+ end
29
+
30
+ def export_path(path)
31
+ self.__add_string('export_path', path)
32
+ end
33
+
34
+ def image(name)
35
+ self.__add_string('image', name)
36
+ end
37
+
38
+ def pull(bool)
39
+ self.__add_boolean('pull', bool)
40
+ end
41
+
42
+ def run_command(commands)
43
+ self.__add_array_of_strings('run_command', commands)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,169 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2014 Ian Chesal
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ require 'packer/builder'
16
+ require 'packer/dataobject'
17
+
18
+ module Packer
19
+ class Builder < Packer::DataObject
20
+ class VirtualBoxISO < Builder
21
+ def initialize
22
+ super
23
+ self.data['type'] = VIRTUALBOX_ISO
24
+ self.add_required(
25
+ 'iso_checksum',
26
+ 'iso_checksum_type',
27
+ 'iso_url',
28
+ 'ssh_username'
29
+ )
30
+ end
31
+
32
+ def iso_checksum(checksum)
33
+ self.__add_string('iso_checksum', checksum)
34
+ end
35
+
36
+ def iso_checksum_type(type)
37
+ self.__add_string('iso_checksum_type', type)
38
+ end
39
+
40
+ def iso_url(url)
41
+ self.__add_string('iso_url', url, %w[iso_urls])
42
+ end
43
+
44
+ def iso_urls(urls)
45
+ self.__add_array_of_strings('iso_urls', urls, %[iso_url])
46
+ end
47
+
48
+ def ssh_username(username)
49
+ self.__add_string('ssh_username', username)
50
+ end
51
+
52
+ def boot_command(commands)
53
+ self.__add_array_of_strings('boot_command', commands)
54
+ end
55
+
56
+ def boot_wait(time)
57
+ self.__add_string('boot_wait',time)
58
+ end
59
+
60
+ def disk_size(megabytes)
61
+ self.__add_integer('disk_size', megabytes)
62
+ end
63
+
64
+ def export_opts(vboxmanage_export_options)
65
+ self.__add_array_of_strings('export_opts', vboxmanage_export_options)
66
+ end
67
+
68
+ def floppy_files(files)
69
+ self.__add_array_of_strings('floppy_files', files)
70
+ end
71
+
72
+ def format(format)
73
+ self.__add_string('format', format)
74
+ end
75
+
76
+ def guest_additions_mode(mode)
77
+ self.__add_string('guest_additions_mode', mode)
78
+ end
79
+
80
+ def guest_additions_path(path)
81
+ self.__add_string('guest_additions_path', path)
82
+ end
83
+
84
+ def guest_additions_sha256(checksum)
85
+ self.__add_string('guest_additions_sha256', checksum)
86
+ end
87
+
88
+ def guest_additions_url(url)
89
+ self.__add_string('guest_additions_url', url)
90
+ end
91
+
92
+ def guest_os_type(ostype)
93
+ self.__add_string('guest_os_type', ostype)
94
+ end
95
+
96
+ def hard_drive_interface(controllertype)
97
+ self.__add_string('hard_drive_interface', controllertype)
98
+ end
99
+
100
+ def headless(bool)
101
+ self.__add_boolean('headless', bool)
102
+ end
103
+
104
+ def http_directory(directory)
105
+ self.__add_string('http_directory', directory)
106
+ end
107
+
108
+ def http_port_min(port_number)
109
+ self.__add_integer('http_port_min', port_number)
110
+ end
111
+
112
+ def http_port_max(port_number)
113
+ self.__add_integer('http_port_max', port_number)
114
+ end
115
+
116
+ def output_directory(directory)
117
+ self.__add_string('output_directory', directory)
118
+ end
119
+
120
+ def shutdown_command(command)
121
+ self.__add_string('shutdown_command', command)
122
+ end
123
+
124
+ def shutdown_timeout(time)
125
+ self.__add_string('shutdown_timeout', time)
126
+ end
127
+
128
+ def ssh_host_port_min(port_number)
129
+ self.__add_integer('ssh_host_port_min', port_number)
130
+ end
131
+
132
+ def ssh_host_port_max(port_number)
133
+ self.__add_integer('ssh_host_port_max', port_number)
134
+ end
135
+
136
+ def ssh_key_path(path)
137
+ self.__add_string('ssh_key_path', path)
138
+ end
139
+
140
+ def ssh_password(password)
141
+ self.__add_string('ssh_password', password)
142
+ end
143
+
144
+ def ssh_port(port_number)
145
+ self.__add_integer('ssh_port', port_number)
146
+ end
147
+
148
+ def ssh_wait_timeout(time)
149
+ self.__add_string('ssh_wait_timeout', time)
150
+ end
151
+
152
+ def vboxmanage(array_of_commands)
153
+ self.__add_array_of_array_of_strings('vboxmanage', array_of_commands)
154
+ end
155
+
156
+ def vboxmanage_post(array_of_commands)
157
+ self.__add_array_of_array_of_strings('vboxmanage_post', array_of_commands)
158
+ end
159
+
160
+ def virtualbox_version_file(file)
161
+ self.__add_string('virtualbox_version_file', file)
162
+ end
163
+
164
+ def vm_name(name)
165
+ self.__add_string('vm_name', name)
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,128 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2014 Ian Chesal
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Packer
17
+ class DataObject
18
+
19
+ attr_accessor :data
20
+ attr_accessor :required
21
+
22
+ def initialize
23
+ self.data = {}
24
+ self.required = []
25
+ end
26
+
27
+ class DataValidationError < StandardError
28
+ end
29
+
30
+ def validate
31
+ self.required.each do |r|
32
+ if (r.is_a? Array) && (r.length > 0)
33
+ if r.length - (r - self.data.keys).length == 0
34
+ raise DataValidationError.new("Missing one required setting from the set #{r}")
35
+ end
36
+ if r.length - (r - self.data.keys).length > 1
37
+ raise DataValidationError.new("Found more than one exclusive setting in data from set #{r}")
38
+ end
39
+ else
40
+ if ! self.data.keys.include? r
41
+ raise DataValidationError.new("Missing required setting #{r}")
42
+ end
43
+ end
44
+ end
45
+ # TODO(ianc) Also validate the data with the packer command?
46
+ true
47
+ end
48
+
49
+ def add_required(*keys)
50
+ keys.each do |k|
51
+ self.required.push(k)
52
+ end
53
+ end
54
+
55
+ def deep_copy
56
+ Marshal.load(Marshal.dump(self.data))
57
+ end
58
+
59
+ class ExclusiveKeyError < StandardError
60
+ end
61
+
62
+ def __exclusive_key_error(key, exclusives)
63
+ exclusives.each do |e|
64
+ if self.data.has_key? e
65
+ raise ExclusiveKeyError.new("Only one of #{exclusives} can be used at a time")
66
+ end
67
+ end
68
+ true
69
+ end
70
+
71
+ def __add_array_of_strings(key, values, exclusives = [])
72
+ self.__exclusive_key_error(key, exclusives)
73
+ raise TypeError.new() unless Array.try_convert(values)
74
+ self.data[key.to_s] = values.to_ary.map{ |c| c.to_s }
75
+ end
76
+
77
+ def __add_array_of_array_of_strings(key, values, exclusives = [])
78
+ self.__exclusive_key_error(key, exclusives)
79
+ raise TypeError.new() unless Array.try_convert(values)
80
+ self.data[key.to_s] = []
81
+ values.each do |v|
82
+ raise TypeError.new() unless Array.try_convert(v)
83
+ self.data[key.to_s].push(v.to_ary.map{ |c| c.to_s })
84
+ end
85
+ end
86
+
87
+ def __add_array_of_hashes(key, values, exclusives = [])
88
+ self.__exclusive_key_error(key, exclusives)
89
+ raise TypeError.new() unless Array.try_convert(values)
90
+ self.data[key.to_s] = []
91
+ values.each do |v|
92
+ raise TypeError.new() unless v.is_a?(Hash)
93
+ self.data[key.to_s].push({})
94
+ v.keys.each do |k|
95
+ self.data[key.to_s][-1][k] = v[k].to_s
96
+ end
97
+ end
98
+ end
99
+
100
+ def __add_string(key, data, exclusives = [])
101
+ self.__exclusive_key_error(key, exclusives)
102
+ self.data[key.to_s] = data.to_s
103
+ end
104
+
105
+ def __add_integer(key, data, exclusives = [])
106
+ self.__exclusive_key_error(key, exclusives)
107
+ self.data[key.to_s] = data.to_i
108
+ end
109
+
110
+ def __add_boolean(key, bool, exclusives = [])
111
+ self.__exclusive_key_error(key, exclusives)
112
+ if bool
113
+ self.data[key.to_s] = true
114
+ else
115
+ self.data[key.to_s] = false
116
+ end
117
+ end
118
+
119
+ def __add_hash(key, data, exclusives = [])
120
+ self.__exclusive_key_error(key, exclusives)
121
+ raise TypeError.new() unless data.is_a?(Hash)
122
+ self.data[key.to_s] = {}
123
+ data.keys.each do |k|
124
+ self.data[key.to_s][k] = data[k].to_s
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,27 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2014 Ian Chesal
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Packer
17
+ class EnvVar
18
+ def method_missing(method_name, *args)
19
+ "{{env `#{method_name}`}}"
20
+ end
21
+
22
+ def respond_to?(symbol, include_private=false)
23
+ # We literally respond to everything...
24
+ true
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2014 Ian Chesal
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Packer
17
+ class Macro
18
+ def method_missing(method_name, *args)
19
+ name = method_name.to_s.slice(0,1).capitalize + method_name.to_s.slice(1..-1)
20
+ "{{ .#{name} }}"
21
+ end
22
+
23
+ def respond_to?(symbol, include_private=false)
24
+ # We literally respond to everything...
25
+ true
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,77 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2014 Ian Chesal
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ require 'packer/postprocessors/all'
16
+ require 'packer/dataobject'
17
+
18
+ module Packer
19
+ class PostProcessor < Packer::DataObject
20
+
21
+ DOCKER_IMPORT = 'docker-import'
22
+ DOCKER_PUSH = 'docker-push'
23
+ VAGRANT = 'vagrant'
24
+
25
+ VALID_POST_PROCESSOR_TYPES = [
26
+ DOCKER_IMPORT,
27
+ DOCKER_PUSH,
28
+ VAGRANT
29
+ ]
30
+
31
+ class UnrecognizedPostProcessorTypeError < StandardError
32
+ end
33
+
34
+ def self.get_postprocessor(type)
35
+ unless validate_type(type)
36
+ raise UnrecognizedPostProcessorTypeError.new("Unrecognized post-processor type #{type}")
37
+ end
38
+ {
39
+ DOCKER_IMPORT => Packer::PostProcessor::DockerImport,
40
+ DOCKER_PUSH => Packer::PostProcessor::DockerPush,
41
+ VAGRANT => Packer::PostProcessor::Vagrant
42
+ }.fetch(type).new
43
+ end
44
+
45
+ def self.types
46
+ VALID_POST_PROCESSOR_TYPES
47
+ end
48
+
49
+ def initialize
50
+ super
51
+ self.add_required('type')
52
+ end
53
+
54
+ def only(buildname)
55
+ unless self.data.has_key? 'only'
56
+ self.data['only'] = []
57
+ end
58
+ self.data['only'] << buildname.to_s
59
+ end
60
+
61
+ def except(buildname)
62
+ unless self.data.has_key? 'except'
63
+ self.data['except'] = []
64
+ end
65
+ self.data['except'] << buildname.to_s
66
+ end
67
+
68
+ def keep_input_artifact(bool)
69
+ self.__add_boolean('keep_input_artifact', bool)
70
+ end
71
+
72
+ private
73
+ def self.validate_type(type)
74
+ VALID_POST_PROCESSOR_TYPES.include? type
75
+ end
76
+ end
77
+ end