packer-config 0.0.3

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