vanagon 0.6.1 → 0.6.2
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.
- checksums.yaml +4 -4
- data/README.md +130 -23
- data/bin/build +0 -4
- data/bin/build_host_info +21 -0
- data/bin/inspect +25 -0
- data/lib/vanagon/driver.rb +17 -8
- data/lib/vanagon/engine/base.rb +11 -2
- data/lib/vanagon/engine/docker.rb +21 -6
- data/lib/vanagon/engine/ec2.rb +75 -0
- data/lib/vanagon/engine/hardware.rb +20 -3
- data/lib/vanagon/engine/local.rb +18 -3
- data/lib/vanagon/engine/pooler.rb +22 -7
- data/lib/vanagon/extensions/hashable.rb +41 -0
- data/lib/vanagon/extensions/ostruct/json.rb +12 -0
- data/lib/vanagon/extensions/set/json.rb +12 -0
- data/lib/vanagon/extensions/string.rb +1 -1
- data/lib/vanagon/platform.rb +2 -0
- data/lib/vanagon/platform/dsl.rb +63 -0
- data/lib/vanagon/platform/osx.rb +6 -0
- data/lib/vanagon/project/dsl.rb +1 -1
- data/lib/vanagon/utilities.rb +10 -4
- data/resources/osx/uninstaller.tool.erb +24 -0
- data/resources/rpm/project.spec.erb +6 -0
- data/spec/lib/vanagon/driver_spec.rb +88 -0
- data/spec/lib/vanagon/engine/docker_spec.rb +6 -0
- data/spec/lib/vanagon/engine/ec2_spec.rb +33 -0
- data/spec/lib/vanagon/engine/hardware_spec.rb +4 -0
- data/spec/lib/vanagon/engine/local_spec.rb +5 -0
- data/spec/lib/vanagon/engine/pooler_spec.rb +5 -0
- data/spec/lib/vanagon/extensions/ostruct/json_spec.rb +16 -0
- data/spec/lib/vanagon/extensions/set/json_spec.rb +17 -0
- data/spec/lib/vanagon/extensions/string_spec.rb +30 -0
- data/spec/lib/vanagon/utilities_spec.rb +1 -1
- metadata +22 -6
- data/resources/windows/wix/componentgroup.wxs.erb +0 -33
- data/resources/windows/wix/project.wxs.erb +0 -34
- data/resources/windows/wix/registryEntries.wxs.erb +0 -47
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'erb'
|
3
|
+
require 'base64'
|
4
|
+
require 'vanagon/engine/base'
|
5
|
+
|
6
|
+
class Vanagon
|
7
|
+
class Engine
|
8
|
+
class Ec2 < Base
|
9
|
+
attr_accessor :ami, :key_name, :userdata, :key, :key_name, :shutdown_behavior
|
10
|
+
attr_accessor :subnet_id, :instance_type
|
11
|
+
|
12
|
+
def initialize(platform, target = nil)
|
13
|
+
super
|
14
|
+
|
15
|
+
@ami = @platform.aws_ami
|
16
|
+
@target_user = @platform.target_user
|
17
|
+
@subnet_id = @platform.aws_subnet_id
|
18
|
+
@userdata = @platform.aws_user_data
|
19
|
+
@region = @platform.aws_region || 'us-east-1'
|
20
|
+
@key_name = @platform.aws_key_name
|
21
|
+
@key = @platform.aws_key
|
22
|
+
@instance_type = @platform.aws_instance_type || "t1.micro"
|
23
|
+
@required_attributes = ["ssh_port", "aws_ami", "aws_key_name"]
|
24
|
+
@shutdown_behavior = @platform.aws_shutdown_behavior
|
25
|
+
|
26
|
+
@ec2 = ::Aws::EC2::Client.new(region: @region)
|
27
|
+
@resource = ::Aws::EC2::Resource.new(client: @ec2)
|
28
|
+
end
|
29
|
+
|
30
|
+
def name
|
31
|
+
'ec2'
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_userdata
|
35
|
+
unless @userdata.nil?
|
36
|
+
Base64.encode64(ERB.new(@userdata).result(binding))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def instances
|
41
|
+
@instances ||= @resource.create_instances({
|
42
|
+
image_id: ami,
|
43
|
+
min_count: 1,
|
44
|
+
max_count: 1,
|
45
|
+
key_name: key_name,
|
46
|
+
instance_type: instance_type,
|
47
|
+
subnet_id: subnet_id,
|
48
|
+
user_data: get_userdata,
|
49
|
+
monitoring: {
|
50
|
+
enabled: false,
|
51
|
+
}
|
52
|
+
})
|
53
|
+
end
|
54
|
+
|
55
|
+
def instance
|
56
|
+
@instance ||= instances.first
|
57
|
+
end
|
58
|
+
|
59
|
+
def select_target
|
60
|
+
puts "Instance created id: #{instance.id}"
|
61
|
+
puts "Created instance waiting for status ok"
|
62
|
+
@ec2.wait_until(:instance_status_ok, instance_ids: [instance.id])
|
63
|
+
puts "Instance running"
|
64
|
+
@target = instance.private_ip_address
|
65
|
+
rescue ::Aws::Waiters::Errors::WaiterFailed => error
|
66
|
+
fail "Failed to wait for ec2 instance to start got error #{error}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def teardown
|
70
|
+
puts "Destroying instance on AWS id: #{instance.id}"
|
71
|
+
instances.batch_terminate!
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -51,15 +51,32 @@ class Vanagon
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def initialize(platform, target)
|
54
|
+
super
|
55
|
+
|
54
56
|
Vanagon::Driver.logger.debug "Hardware engine invoked."
|
55
|
-
@name = 'hardware'
|
56
|
-
@platform = platform
|
57
57
|
@build_hosts = platform.build_hosts
|
58
58
|
# Redis is the only backend supported in lock_manager currently
|
59
59
|
@lockman = LockManager.new(type: 'redis', server: LOCK_MANAGER_HOST)
|
60
|
-
super
|
61
60
|
@required_attributes << "build_hosts"
|
62
61
|
end
|
62
|
+
|
63
|
+
# Get the engine name
|
64
|
+
def name
|
65
|
+
'hardware'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get the first build host name to build on
|
69
|
+
def build_host_name
|
70
|
+
if @build_host_name.nil?
|
71
|
+
validate_platform
|
72
|
+
# For now, get the first build host. In the future, lock management
|
73
|
+
# will be pushed into the pooler (or something that wraps it), and
|
74
|
+
# the hardware engine can go away.
|
75
|
+
@build_host_name = @build_hosts.first
|
76
|
+
end
|
77
|
+
|
78
|
+
@build_host_name
|
79
|
+
end
|
63
80
|
end
|
64
81
|
end
|
65
82
|
end
|
data/lib/vanagon/engine/local.rb
CHANGED
@@ -7,9 +7,8 @@ class Vanagon
|
|
7
7
|
class Local < Base
|
8
8
|
|
9
9
|
def initialize(platform, target = nil)
|
10
|
-
|
11
|
-
|
12
|
-
super
|
10
|
+
# local engine can't be used with a target
|
11
|
+
super(platform, 'local machine')
|
13
12
|
|
14
13
|
# We inherit a set of required attributes from Base,
|
15
14
|
# and rather than instantiate a new empty array for
|
@@ -18,6 +17,21 @@ class Vanagon
|
|
18
17
|
@required_attributes.clear
|
19
18
|
end
|
20
19
|
|
20
|
+
# Get the engine name
|
21
|
+
def name
|
22
|
+
'local'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the target name to build on
|
26
|
+
def build_host_name
|
27
|
+
if @build_host_name.nil?
|
28
|
+
validate_platform
|
29
|
+
@build_host_name = @target
|
30
|
+
end
|
31
|
+
|
32
|
+
@build_host_name
|
33
|
+
end
|
34
|
+
|
21
35
|
# Dispatches the command for execution
|
22
36
|
def dispatch(command, return_output = false)
|
23
37
|
Vanagon::Utilities.local_command(command, return_command_output: return_output)
|
@@ -31,6 +45,7 @@ class Vanagon
|
|
31
45
|
FileUtils.mkdir_p("output")
|
32
46
|
FileUtils.cp_r(Dir.glob("#{@remote_workdir}/output/*"), "output/")
|
33
47
|
end
|
48
|
+
|
34
49
|
end
|
35
50
|
end
|
36
51
|
end
|
@@ -7,11 +7,26 @@ class Vanagon
|
|
7
7
|
|
8
8
|
# The vmpooler_template is required to use the pooler engine
|
9
9
|
def initialize(platform, target = nil)
|
10
|
+
super
|
11
|
+
|
10
12
|
@pooler = "http://vmpooler.delivery.puppetlabs.net"
|
11
13
|
@token = load_token
|
12
|
-
super
|
13
14
|
@required_attributes << "vmpooler_template"
|
14
|
-
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get the engine name
|
18
|
+
def name
|
19
|
+
'pooler'
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return the vmpooler template name to build on
|
23
|
+
def build_host_name
|
24
|
+
if @build_host_template_name.nil?
|
25
|
+
validate_platform
|
26
|
+
@build_host_template_name = @platform.vmpooler_template
|
27
|
+
end
|
28
|
+
|
29
|
+
@build_host_template_name
|
15
30
|
end
|
16
31
|
|
17
32
|
# This method loads the pooler token from one of two locations
|
@@ -35,12 +50,12 @@ class Vanagon
|
|
35
50
|
response = Vanagon::Utilities.http_request(
|
36
51
|
"#{@pooler}/vm",
|
37
52
|
'POST',
|
38
|
-
'{"' +
|
53
|
+
'{"' + build_host_name + '":"1"}',
|
39
54
|
{ 'X-AUTH-TOKEN' => @token }
|
40
55
|
)
|
41
56
|
if response["ok"]
|
42
|
-
@target = response[
|
43
|
-
Vanagon::Driver.logger.info "Reserving #{@target} (#{
|
57
|
+
@target = response[build_host_name]['hostname'] + '.' + response['domain']
|
58
|
+
Vanagon::Driver.logger.info "Reserving #{@target} (#{build_host_name}) [#{@token ? 'token used' : 'no token used'}]"
|
44
59
|
|
45
60
|
tags = {
|
46
61
|
'tags' => {
|
@@ -51,13 +66,13 @@ class Vanagon
|
|
51
66
|
}
|
52
67
|
|
53
68
|
Vanagon::Utilities.http_request(
|
54
|
-
"#{@pooler}/vm/#{response[
|
69
|
+
"#{@pooler}/vm/#{response[build_host_name]['hostname']}",
|
55
70
|
'PUT',
|
56
71
|
tags.to_json,
|
57
72
|
{ 'X-AUTH-TOKEN' => @token }
|
58
73
|
)
|
59
74
|
else
|
60
|
-
raise Vanagon::Error, "Something went wrong getting a target vm to build on, maybe the pool for #{
|
75
|
+
raise Vanagon::Error, "Something went wrong getting a target vm to build on, maybe the pool for #{build_host_name} is empty?"
|
61
76
|
end
|
62
77
|
end
|
63
78
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# This is bad, and I feel bad. This will let you append
|
2
|
+
# broadly useful Hash and JSON casting on any class that
|
3
|
+
# includes it. But it's pretty naive, in that it just turns
|
4
|
+
# attributes names into keys while retaining their
|
5
|
+
# associated values.
|
6
|
+
module HashableAttributes
|
7
|
+
# @return [Hash] Converts an object to a hash with keys representing
|
8
|
+
# each attribute (as symbols) and their corresponding values
|
9
|
+
def to_hash
|
10
|
+
instance_variables.each_with_object({}) do |var, hash|
|
11
|
+
hash[var.to_s.delete("@")] = instance_variable_get(var)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
alias_method :to_h, :to_hash
|
15
|
+
|
16
|
+
def to_json(*options)
|
17
|
+
to_hash.to_json options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Vanagon classes generally don't implement JSON or Hash functionality
|
22
|
+
# so those need to be monkey-patched for useful inspection.
|
23
|
+
class Vanagon
|
24
|
+
class Platform
|
25
|
+
include HashableAttributes
|
26
|
+
end
|
27
|
+
|
28
|
+
class Common
|
29
|
+
class Pathname
|
30
|
+
include HashableAttributes
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Component
|
35
|
+
include HashableAttributes
|
36
|
+
end
|
37
|
+
|
38
|
+
class Patch
|
39
|
+
include HashableAttributes
|
40
|
+
end
|
41
|
+
end
|
data/lib/vanagon/platform.rb
CHANGED
@@ -7,6 +7,8 @@ class Vanagon
|
|
7
7
|
attr_accessor :servicetype, :patch, :architecture, :codename, :os_name, :os_version
|
8
8
|
attr_accessor :docker_image, :ssh_port, :rpmbuild, :install, :platform_triple
|
9
9
|
attr_accessor :target_user, :package_type, :find, :sort, :build_hosts, :copy, :cross_compiled
|
10
|
+
attr_accessor :aws_ami, :aws_user_data, :aws_shutdown_behavior, :aws_key_name, :aws_region, :aws_key
|
11
|
+
attr_accessor :aws_instance_type, :aws_vpc_id, :aws_subnet_id
|
10
12
|
|
11
13
|
# Platform names currently contain some information about the platform. Fields
|
12
14
|
# within the name are delimited by the '-' character, and this regex can be used to
|
data/lib/vanagon/platform/dsl.rb
CHANGED
@@ -228,6 +228,55 @@ class Vanagon
|
|
228
228
|
@platform.docker_image = name
|
229
229
|
end
|
230
230
|
|
231
|
+
# Set the ami for the platform to use
|
232
|
+
#
|
233
|
+
# @param ami [String] the ami id used.
|
234
|
+
def aws_ami(ami)
|
235
|
+
@platform.aws_ami = ami
|
236
|
+
end
|
237
|
+
|
238
|
+
# Set the user data used in AWS to do setup. Like cloud-config
|
239
|
+
#
|
240
|
+
# @param userdata [String] a string used to send to the node to do the intial setup
|
241
|
+
def aws_user_data(userdata)
|
242
|
+
@platform.aws_user_data = userdata
|
243
|
+
end
|
244
|
+
|
245
|
+
# Set the region, this defaults to us-east-1
|
246
|
+
#
|
247
|
+
# @param region [String] a string used to setup the region
|
248
|
+
def aws_region(region = 'us-east-1')
|
249
|
+
@platform.aws_region = region
|
250
|
+
end
|
251
|
+
|
252
|
+
# Set the shutdown behavior for aws. This will default to terminate the instance on shutdown
|
253
|
+
#
|
254
|
+
# @param shutdown_behavior [String] a string used to set the shutdown behavior
|
255
|
+
def aws_shutdown_behavior(shutdown_behavior = 'terminate')
|
256
|
+
@platform.aws_shutdown_behavior = shutdown_behavior
|
257
|
+
end
|
258
|
+
|
259
|
+
# Set the key_name used. This should already exist on AWS.
|
260
|
+
#
|
261
|
+
# @param key_name [String] this defaults to the keyname vanagon. Can be set to any
|
262
|
+
def aws_key_name(key_name = 'vanagon')
|
263
|
+
@platform.aws_key_name = key_name
|
264
|
+
end
|
265
|
+
|
266
|
+
# Set the instaince type. This defaults to t1.micro which is the free instance
|
267
|
+
#
|
268
|
+
# @param instance_type [String] a string to define the instaince type
|
269
|
+
def aws_instance_type(instance_type = 't1.micro')
|
270
|
+
@platform.aws_instance_type = instance_type
|
271
|
+
end
|
272
|
+
|
273
|
+
# Set the subnet_id. Use this to setup a subnet for your VPC to use.
|
274
|
+
#
|
275
|
+
# @param subnet_id[String] a string to define the subnet_id in AWS
|
276
|
+
def aws_subnet_id(subnet_id)
|
277
|
+
@platform.aws_subnet_id = subnet_id
|
278
|
+
end
|
279
|
+
|
231
280
|
# Set the port for ssh to use if it's not 22
|
232
281
|
#
|
233
282
|
# @param port [Integer] port number for ssh
|
@@ -235,6 +284,20 @@ class Vanagon
|
|
235
284
|
@platform.ssh_port = port
|
236
285
|
end
|
237
286
|
|
287
|
+
# Set the target user to login with. Defaults to root.
|
288
|
+
#
|
289
|
+
# @param user[String] a user string to login with.
|
290
|
+
def target_user(user = "root")
|
291
|
+
@platform.target_user = user
|
292
|
+
end
|
293
|
+
|
294
|
+
# Set the target ip address or hostname to start build
|
295
|
+
#
|
296
|
+
# @param target_host[String] a host string to login with.
|
297
|
+
def target_host(target_host)
|
298
|
+
@platform.target_host = target_host
|
299
|
+
end
|
300
|
+
|
238
301
|
# Set the platform_triple for the platform
|
239
302
|
#
|
240
303
|
# @param triple[String] platform_triple for use in building out compiled
|
data/lib/vanagon/platform/osx.rb
CHANGED
@@ -25,8 +25,11 @@ class Vanagon
|
|
25
25
|
# Setup build directories
|
26
26
|
["bash -c 'mkdir -p $(tempdir)/osx/build/{dmg,pkg,scripts,resources,root,payload,plugins}'",
|
27
27
|
"mkdir -p $(tempdir)/osx/build/root/#{project.name}-#{project.version}",
|
28
|
+
"mkdir -p $(tempdir)/osx/build/pkg",
|
28
29
|
# Grab distribution xml, scripts and other external resources
|
29
30
|
"cp #{project.name}-installer.xml $(tempdir)/osx/build/",
|
31
|
+
#copy the uninstaller to the pkg dir, where eventually the installer will go too
|
32
|
+
"cp #{project.name}-uninstaller.tool $(tempdir)/osx/build/pkg/",
|
30
33
|
"cp scripts/* $(tempdir)/osx/build/scripts/",
|
31
34
|
"if [ -d resources/osx/productbuild ] ; then cp -r resources/osx/productbuild/* $(tempdir)/osx/build/; fi",
|
32
35
|
# Unpack the project
|
@@ -73,6 +76,9 @@ class Vanagon
|
|
73
76
|
FileUtils.chmod 0755, File.join(script_dir, script_file)
|
74
77
|
end
|
75
78
|
|
79
|
+
erb_file(File.join(VANAGON_ROOT, 'resources', 'osx', 'uninstaller.tool.erb'), File.join(workdir, "#{name}-uninstaller.tool"), false, { :binding => binding })
|
80
|
+
FileUtils.chmod 0755, File.join(workdir, "#{name}-uninstaller.tool")
|
81
|
+
|
76
82
|
# Probably a better way to do this, but OSX tends to need some extra stuff
|
77
83
|
FileUtils.cp_r("resources/osx/.", resources_dir) if File.exist?("resources/osx/")
|
78
84
|
end
|
data/lib/vanagon/project/dsl.rb
CHANGED
@@ -194,7 +194,7 @@ class Vanagon
|
|
194
194
|
#
|
195
195
|
# @param name [String] name of component to add. must be present in configdir/components and named $name.rb currently
|
196
196
|
def component(name)
|
197
|
-
puts "Loading #{name}"
|
197
|
+
puts "Loading #{name}" if @project.settings[:verbose]
|
198
198
|
if @include_components.empty? or @include_components.include?(name)
|
199
199
|
component = Vanagon::Component.load_component(name, File.join(Vanagon::Driver.configdir, "components"), @project.settings, @project.platform)
|
200
200
|
@project.components << component
|
data/lib/vanagon/utilities.rb
CHANGED
@@ -129,18 +129,24 @@ class Vanagon
|
|
129
129
|
# @return [true] If the block succeeds, true is returned
|
130
130
|
# @raise [Vanagon::Error] if the block fails after the retries are exhausted, an error is raised
|
131
131
|
def retry_with_timeout(tries = 5, timeout = 1, &blk)
|
132
|
-
|
133
|
-
|
132
|
+
error = nil
|
133
|
+
tries.to_i.times do
|
134
|
+
Timeout::timeout(timeout.to_i) do
|
134
135
|
begin
|
135
136
|
blk.call
|
136
137
|
return true
|
137
|
-
rescue
|
138
|
+
rescue => e
|
138
139
|
warn 'An error was encountered evaluating block. Retrying..'
|
140
|
+
error = e
|
139
141
|
end
|
140
142
|
end
|
141
143
|
end
|
142
144
|
|
143
|
-
|
145
|
+
message = "Block failed maximum number of #{tries} tries"
|
146
|
+
message += "\n with error #{error.message}" unless error.nil?
|
147
|
+
message += "\nExiting..."
|
148
|
+
raise error, message unless error.nil?
|
149
|
+
raise Vanagon::Error, "Block failed maximum number of #{tries} tries"
|
144
150
|
end
|
145
151
|
|
146
152
|
# Simple wrapper around git command line executes the given commands and
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
<%- if has_services? -%>
|
4
|
+
<%- get_services.each do |service| -%>
|
5
|
+
echo "Unloading service <%= service.name %>..."
|
6
|
+
/bin/launchctl unload <%= service.service_file %>
|
7
|
+
echo "OK"
|
8
|
+
echo "Removing service file <%= service.service_file %>..."
|
9
|
+
/bin/rm <%= service.service_file %>
|
10
|
+
echo "OK"
|
11
|
+
<%- end -%>
|
12
|
+
<%- end -%>
|
13
|
+
|
14
|
+
echo "Removing identifier: <%= @identifier-%>.<%= @name -%>..."
|
15
|
+
if /usr/sbin/pkgutil --files <%= @identifier-%>.<%= @name -%> >/dev/null 2>&1 ; then
|
16
|
+
/usr/sbin/pkgutil --forget <%= @identifier-%>.<%= @name -%>
|
17
|
+
|
18
|
+
fi
|
19
|
+
echo "OK"
|
20
|
+
|
21
|
+
echo "Removing Files"
|
22
|
+
/bin/rm -Rf <%= get_directories.map {|d| d.path}.join(" ").to_s -%>
|
23
|
+
|
24
|
+
echo "OK"
|