Class: BuildUbuntuAmi

Inherits:
Object
  • Object
show all
Defined in:
lib/build_ubuntu_ami.rb

Constant Summary collapse

USER_DATA =
File.read(File.join(File.dirname(__FILE__),'..','data','user_data.sh.erb'))

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ BuildUbuntuAmi

Returns a new instance of BuildUbuntuAmi.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/build_ubuntu_ami.rb', line 26

def initialize(opts={})
  opts = self.class.default_options.merge(opts)
  puts "Configuration:"
  (self.class.default_options.keys - [:kernel]).each do |attr|
    puts "  #{attr}: #{opts[attr]}"
    self.send("#{attr}=", opts[attr])
  end
  self.custom_user_script = opts[:custom_user_script]

  find_canonical_ubuntu_ami
  puts "  canonical ami: #{canonical_ami}"
  puts "  kernel: #{kernel}"

  @now = Time.now.strftime('%Y%m%d-%H%M')
  puts "  description: #{description}"
end

Instance Attribute Details

#archObject

Returns the value of attribute arch.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def arch
  @arch
end

#brandObject

Returns the value of attribute brand.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def brand
  @brand
end

#canonical_amiObject

Returns the value of attribute canonical_ami.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def canonical_ami
  @canonical_ami
end

#codenameObject

Returns the value of attribute codename.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def codename
  @codename
end

#custom_user_scriptObject

Returns the value of attribute custom_user_script.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def custom_user_script
  @custom_user_script
end

#flavorObject

Returns the value of attribute flavor.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def flavor
  @flavor
end

#groupObject

Returns the value of attribute group.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def group
  @group
end

#kernelObject

Returns the value of attribute kernel.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def kernel
  @kernel
end

#key_nameObject

Returns the value of attribute key_name.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def key_name
  @key_name
end

#nowObject

Returns the value of attribute now.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def now
  @now
end

#regionObject

Returns the value of attribute region.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def region
  @region
end

#serverObject

Returns the value of attribute server.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def server
  @server
end

#sizeObject

Returns the value of attribute size.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def size
  @size
end

#snapshotObject

Returns the value of attribute snapshot.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def snapshot
  @snapshot
end

#volumeObject

Returns the value of attribute volume.



8
9
10
# File 'lib/build_ubuntu_ami.rb', line 8

def volume
  @volume
end

Class Method Details

.default_optionsObject



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/build_ubuntu_ami.rb', line 12

def self.default_options
  {
    :region   => 'us-east-1',
    :flavor   => 'm1.small',
    :brand    => 'My',
    :size     => 20,
    :codename => 'precise',
    :key_name => 'default',
    :group    => 'default',
    :arch     => 'amd64',
    :kernel   => nil
  }
end

Instance Method Details

#block_device_mappingObject



78
79
80
# File 'lib/build_ubuntu_ami.rb', line 78

def block_device_mapping
  [{ "DeviceName" => root_device, "SnapshotId" => snapshot.id, "VolumeSize" => size, "DeleteOnTermination" => true }]
end

#build!Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/build_ubuntu_ami.rb', line 138

def build!
  launch_server!
  launch_volume!

  puts "waiting for user_data to complete and server to shut down..."
  puts "Follow along by running:"
  puts "  ssh -l #{server.username} #{server.dns_name} 'tail -f /var/log/user-data.log'"
  server.wait_for(60*60*24*7) { state == 'stopped' }

  puts "Detaching volume"
  volume.server = nil

  take_snapshot!

  # Register AMI
  res = fog.register_image(description, description, root_device, block_device_mapping, 'KernelId' => kernel, 'Architecture' => image_arch)
  puts "Registered imageId #{res.body['imageId']}"

  cleanup!

end

#cleanup!Object



131
132
133
134
135
136
# File 'lib/build_ubuntu_ami.rb', line 131

def cleanup!
  puts "Deleting #{volume.id}"
  volume.destroy
  puts "Terminating #{server.id}"
  server.destroy
end

#descriptionObject



66
67
68
# File 'lib/build_ubuntu_ami.rb', line 66

def description
  "#{brand}-#{codename}-#{arch}-#{now}"
end

#ebs_deviceObject



70
71
72
# File 'lib/build_ubuntu_ami.rb', line 70

def ebs_device
  '/dev/sdi'
end

#find_canonical_ubuntu_amiObject

Return the Ubuntu AMI with the architecture for flavor



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/build_ubuntu_ami.rb', line 44

def find_canonical_ubuntu_ami
  url = "http://uec-images.ubuntu.com/query/#{codename}/server/released.current.txt"
  data = open(url).read.split("\n").map{|l| l.split}.detect do |ary|
    ary[4] == 'ebs' &&
      ary[5] == arch &&
      ary[6] == region &&
      ary[9] == 'paravirtual'
  end

  self.canonical_ami = data[7]
  self.kernel ||= data[8]
end

#fogObject



90
91
92
# File 'lib/build_ubuntu_ami.rb', line 90

def fog
  @fog ||= Fog::Compute.new(:provider => 'AWS', :region => region)
end

#image_archObject



57
58
59
60
61
62
63
64
# File 'lib/build_ubuntu_ami.rb', line 57

def image_arch
  case arch
  when 'amd64'
    'x86_64'
  else
    arch
  end
end

#image_nameObject



82
83
84
# File 'lib/build_ubuntu_ami.rb', line 82

def image_name
  "#{codename}-server-cloudimg-#{arch}"
end

#image_urlObject



86
87
88
# File 'lib/build_ubuntu_ami.rb', line 86

def image_url
  "http://uec-images.ubuntu.com/#{codename}/current/#{image_name}.tar.gz"
end

#launch_server!Object



94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/build_ubuntu_ami.rb', line 94

def launch_server!
  puts "Launching server..."
  self.server = fog.servers.create({
    :flavor_id => flavor,
    :image_id => canonical_ami,
    :groups => [group],
    :key_name => key_name,
    :user_data => user_data
  })
  server.wait_for { ready? }
  puts "Launched #{server.id}; #{server.dns_name}; waiting for it to be available."
end

#launch_volume!Object



107
108
109
110
111
# File 'lib/build_ubuntu_ami.rb', line 107

def launch_volume!
  self.volume = server.volumes.create(:size => size, :device => ebs_device)
  puts "Attaching volume #{volume.id}"
  volume.wait_for { state == 'in-use' }
end

#root_deviceObject



74
75
76
# File 'lib/build_ubuntu_ami.rb', line 74

def root_device
  '/dev/sda1'
end

#snapshot_descriptionObject



113
114
115
# File 'lib/build_ubuntu_ami.rb', line 113

def snapshot_description
  "#{description} root volume"
end

#take_snapshot!Object



117
118
119
120
121
122
123
124
# File 'lib/build_ubuntu_ami.rb', line 117

def take_snapshot!
  puts "Waiting for volume to detach..."
  volume.wait_for { state == 'available' }
  puts "Taking snapshot #{snapshot_description} from #{volume.id}"
  self.snapshot = volume.snapshots.create(:description => snapshot_description)
  puts "Creating snapshot #{snapshot.id}"
  snapshot.wait_for { ready? }
end

#user_dataObject



126
127
128
129
# File 'lib/build_ubuntu_ami.rb', line 126

def user_data
  @user_data ||= USER_DATA
  ERB.new(@user_data).result(binding)
end