image_optimize 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +48 -0
- data/LICENSE +13 -0
- data/README.md +128 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/image_optimize +22 -0
- data/image_optimize.gemspec +24 -0
- data/lib/api_client_15.rb +86 -0
- data/lib/app/image_optimizer.rb +195 -0
- data/lib/image_bundle.rb +19 -0
- data/lib/image_bundle/image_bundle_base.rb +116 -0
- data/lib/image_bundle/image_bundle_ec2.rb +131 -0
- data/lib/image_bundle/image_bundle_ec2_ebs.rb +77 -0
- data/lib/image_bundle/image_bundle_ec2_s3.rb +114 -0
- data/lib/mixins/command.rb +40 -0
- data/lib/mixins/common.rb +23 -0
- data/rightscale/rightscript.sh +189 -0
- data/setup.sh +40 -0
- data/spec/api_client_spec.rb +39 -0
- data/spec/command_spec.rb +43 -0
- data/spec/image_bundle_ec2_spec.rb +87 -0
- data/spec/image_bundle_spec.rb +97 -0
- data/spec/image_optimizer_spec.rb +194 -0
- data/test/image_optimize_test.rb +50 -0
- metadata +47 -6
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p448
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
image_optimize (1.0.1)
|
5
|
+
mime-types (= 2.0)
|
6
|
+
right_api_client (= 1.5.15)
|
7
|
+
trollop (= 2.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
coderay (1.1.0)
|
13
|
+
diff-lcs (1.2.5)
|
14
|
+
json (1.8.1)
|
15
|
+
method_source (0.8.2)
|
16
|
+
mime-types (2.0)
|
17
|
+
pry (0.9.12.6)
|
18
|
+
coderay (~> 1.0)
|
19
|
+
method_source (~> 0.8)
|
20
|
+
slop (~> 3.4)
|
21
|
+
rake (10.3.0)
|
22
|
+
rest-client (1.6.7)
|
23
|
+
mime-types (>= 1.16)
|
24
|
+
right_api_client (1.5.15)
|
25
|
+
json
|
26
|
+
rest-client (~> 1.6)
|
27
|
+
right_api_provision (0.2.1)
|
28
|
+
right_api_client (= 1.5.15)
|
29
|
+
rspec (2.14.1)
|
30
|
+
rspec-core (~> 2.14.0)
|
31
|
+
rspec-expectations (~> 2.14.0)
|
32
|
+
rspec-mocks (~> 2.14.0)
|
33
|
+
rspec-core (2.14.8)
|
34
|
+
rspec-expectations (2.14.5)
|
35
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
36
|
+
rspec-mocks (2.14.6)
|
37
|
+
slop (3.5.0)
|
38
|
+
trollop (2.0)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
image_optimize!
|
45
|
+
pry
|
46
|
+
rake
|
47
|
+
right_api_provision
|
48
|
+
rspec (~> 2.14)
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2014 RightScale, Inc.
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
Image Optimizer
|
2
|
+
===============
|
3
|
+
|
4
|
+
Bundle a running VM into a new image for use on next launch.
|
5
|
+
|
6
|
+
Useful for drastically reducing boot times in your auto-scaling tier.
|
7
|
+
|
8
|
+
Basic Workflow
|
9
|
+
--------------
|
10
|
+
1. Launch a EC2 instance from a base OS image.
|
11
|
+
2. Converge system into whatever you want it to be (i.e. application server)
|
12
|
+
3. Prepare the system for snapshotting. (see [clean_for_rebundle](https://github.com/caryp/clean_for_rebundle) project)
|
13
|
+
3. Install and run image_optimize
|
14
|
+
4. Next launch will be optimized!!
|
15
|
+
|
16
|
+
Requirements
|
17
|
+
------------
|
18
|
+
* EC2 Cloud only
|
19
|
+
* VMs must be launched via the [RightScale Platform](www.rightscale.com)
|
20
|
+
|
21
|
+
Usage
|
22
|
+
-----
|
23
|
+
|
24
|
+
image_optimize [options]
|
25
|
+
|
26
|
+
where [options] are:
|
27
|
+
|
28
|
+
--verbose, -v: If set will enable debug logging. WARNING: will write ec2 creds to log if set!!
|
29
|
+
--prefix, -r <s>: Prefix to add to the optimized image name. Helps when searching for your optimized images. (Default: optimized-image)
|
30
|
+
--description, -d <s>: Description to add to optimized images (default: Cached image)
|
31
|
+
--api-user, -u <s>: RightScale Dashboard User email. Not needed if API_USER_EMAIL environment variable is set.
|
32
|
+
--api-password, -p <s>: RightScale Dashboard User email. Not needed if API_USER_PASSWORD environment variable is set.
|
33
|
+
--cleanup, --no-cleanup, -c: Don't do any cleanup on VM before snapshotting. Useful for debugging. (Default: true)
|
34
|
+
--aws-access-key, -k: EC2 Account Access Key. Not needed if AWS_ACCESS_KEY environment variable is set.
|
35
|
+
--aws-secret-key, -s: EC2 Account Secret. Not needed if AWS_SECRET_KEY environment variable is set.
|
36
|
+
--aws-account-number, -a: EC2 Account ID. Not needed if AWS_ACCOUNT_NUMBER environment variable is set. Required for S3 images only.
|
37
|
+
--aws-image-type, -w <s>: The type of image to create from this VM. Must be either 'EBS' or 'S3'. (default: EBS)
|
38
|
+
--aws-kernel-id, -e <s>: Kernel to use instead of what the VM is running. i.e. 'aki-fc8f11cc'. For a current list of IDs see http://goo.gl/dOS0mB.
|
39
|
+
--aws-s3-key-path, -y <s>: location to file containing EC2 account key. S3 images only. (Default: /tmp/certs/x509.key)
|
40
|
+
--aws-s3-cert-path, -t <s>: location to file containing EC2 account cert. S3 images only. (Default: /tmp/certs/x509.cert)
|
41
|
+
--aws-s3-image-bucket, -i <s>: The bucket name for optimized S3 images (must be url safe). S3 images only (default: optimized-images)
|
42
|
+
--aws-s3-bundle-directory, -b <s>: The local directory where the image bundle will be stored before uploading to S3. NOTE: this must have enough free space to hold
|
43
|
+
the image bundle. (Default: /mnt/ephemeral/bundle)
|
44
|
+
--aws-s3-bundle-no-filter, -n: If set, will disable the default filtering used by the ec2-bundle-vol command. WARNING: setting this option could leave ssh keys or
|
45
|
+
other secrets on your
|
46
|
+
--version, -o: Print version and exit
|
47
|
+
--help, -h: Show this message
|
48
|
+
|
49
|
+
|
50
|
+
Known Limitations
|
51
|
+
------------------
|
52
|
+
* When creating S3 backed (instance store) images on AWS, the `--aws-s3-image-bucket` will not be created -- make sure it exists.
|
53
|
+
* Currently will only map up to 4 ephemeral drives to EBS image. Some EC2 instance-types support up to 24.
|
54
|
+
* Only tested on Ubuntu 12.04"
|
55
|
+
|
56
|
+
|
57
|
+
Development
|
58
|
+
-----------
|
59
|
+
To run this locally, setup the required environment prerequisites:
|
60
|
+
|
61
|
+
> ./setup.sh
|
62
|
+
|
63
|
+
Run the spec tests:
|
64
|
+
|
65
|
+
> bundle exec rake spec
|
66
|
+
|
67
|
+
Setup a `.secrets/creds` file in the root of the project that defines:
|
68
|
+
|
69
|
+
export API_USER_EMAIL=you@example.com
|
70
|
+
export API_USER_PASSWORD=your_rightscale_password
|
71
|
+
|
72
|
+
export AWS_SECRET_KEY=yoursecretkey
|
73
|
+
export AWS_ACCESS_KEY=youraccesskey
|
74
|
+
|
75
|
+
# needed for S3 (instance store) images only
|
76
|
+
export AWS_ACCOUNT_NUMBER=your_account_number
|
77
|
+
export AWS_S3_IMAGE_BUCKET=my_image_bucket
|
78
|
+
|
79
|
+
Then add your credentials to the environment and run the script using the system's ruby interpreter:
|
80
|
+
|
81
|
+
> source .secrets/creds
|
82
|
+
> bundle exec ruby bin/image_optimize
|
83
|
+
|
84
|
+
|
85
|
+
Integration Testing
|
86
|
+
-------------------
|
87
|
+
Follow the "development" directions (above), then rsync this project to VM:
|
88
|
+
|
89
|
+
> rsync -avz --exclude=.git . root@<ip_addr>:/usr/local/src/image_optimize
|
90
|
+
|
91
|
+
Where `<ip_addr>` is the IP address of the VM you plan to test on.
|
92
|
+
SSH into the VM and run the setup script to install package prerequisites:
|
93
|
+
|
94
|
+
> sudo -i
|
95
|
+
> cd /usr/local/src/image_optimize
|
96
|
+
> source ./setup
|
97
|
+
|
98
|
+
On the VM, run the tests
|
99
|
+
|
100
|
+
> export IMAGE_TYPE=<type> ; bundle exec rake test
|
101
|
+
|
102
|
+
Where `<type>` is either `EBS` or `S3` images.
|
103
|
+
|
104
|
+
|
105
|
+
Future
|
106
|
+
------
|
107
|
+
* automate integration testing on EBS and S3 instances
|
108
|
+
* break out rightscale specific calls into 'manager' interface to support different management platforms
|
109
|
+
* break out system command calls into 'platform' interface to enable multi-distro support
|
110
|
+
|
111
|
+
|
112
|
+
License
|
113
|
+
-------
|
114
|
+
Author: cary@rightscale.com
|
115
|
+
Copyright 2014 RightScale, Inc.
|
116
|
+
|
117
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
118
|
+
you may not use this file except in compliance with the License.
|
119
|
+
You may obtain a copy of the License at
|
120
|
+
|
121
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
122
|
+
|
123
|
+
Unless required by applicable law or agreed to in writing, software
|
124
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
125
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
126
|
+
See the License for the specific language governing permissions and
|
127
|
+
limitations under the License.
|
128
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Author: cary@rightscale.com
|
2
|
+
# Copyright 2014 RightScale, Inc.
|
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
|
+
|
17
|
+
require "bundler/gem_tasks"
|
18
|
+
|
19
|
+
begin
|
20
|
+
require 'rspec/core/rake_task'
|
21
|
+
|
22
|
+
task :default => :spec
|
23
|
+
|
24
|
+
desc "Run all unit tests in spec directory"
|
25
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
26
|
+
t.pattern = 'spec/**/*_spec.rb'
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Run all integration tests in spec directory"
|
30
|
+
RSpec::Core::RakeTask.new(:test) do |t|
|
31
|
+
t.pattern = 'test/**/*_test.rb'
|
32
|
+
end
|
33
|
+
|
34
|
+
rescue LoadError
|
35
|
+
STDERR.puts "\n*** RSpec not available. (sudo) gem install rspec to run unit tests. ***\n\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Create a tarball for non-gem distribution"
|
39
|
+
task :tarball do |t|
|
40
|
+
version = File.open("VERSION", "r") { |f| f.read }
|
41
|
+
filename = "image_optimize_#{version}.tar"
|
42
|
+
puts "Creating tarball #{filename}"
|
43
|
+
puts `mkdir ./pkg ; tar cvf pkg/image_optimize-#{version}.tar bin/ lib/ VERSION Gemfile Gemfile.lock`
|
44
|
+
puts "success!"
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.1
|
data/bin/image_optimize
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Author: cary@rightscale.com
|
4
|
+
# Copyright 2014 RightScale, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'app', 'image_optimizer'))
|
21
|
+
|
22
|
+
optimizer = ImageOptimize::Optimizer.new.run
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
gem = Gem::Specification.new do |gem|
|
6
|
+
gem.name = 'image_optimize'
|
7
|
+
gem.version = File.open("VERSION", "r") { |f| f.read }
|
8
|
+
gem.authors = ['caryp']
|
9
|
+
gem.email = ['cary@rightscale.com']
|
10
|
+
gem.description = %q{Bundle a running server into a new image that will be used on next launch}
|
11
|
+
gem.summary = %q{Bundle a running server into a new image that will be used on next launch}
|
12
|
+
gem.homepage = ''
|
13
|
+
|
14
|
+
gem.files = `git ls-files -z`.split("\x0")
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ['lib']
|
18
|
+
gem.add_dependency 'mime-types', '2.0'
|
19
|
+
gem.add_dependency 'right_api_client', '1.5.15'
|
20
|
+
gem.add_dependency 'trollop', '2.0'
|
21
|
+
gem.add_development_dependency 'rake'
|
22
|
+
gem.add_development_dependency 'rspec', '~>2.14'
|
23
|
+
gem.add_development_dependency 'pry'
|
24
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Author: cary@rightscale.com
|
2
|
+
# Copyright 2014 RightScale, Inc.
|
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
|
+
|
17
|
+
require 'right_api_client'
|
18
|
+
require 'logger'
|
19
|
+
|
20
|
+
module RightScale
|
21
|
+
|
22
|
+
# Create an instance facing or user base API client
|
23
|
+
class ApiClient15
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@log ||= Logger.new(STDOUT)
|
27
|
+
parse_user_data
|
28
|
+
end
|
29
|
+
|
30
|
+
def log(logger)
|
31
|
+
@log = logger
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_client(type, user=nil, password=nil)
|
35
|
+
case type
|
36
|
+
when :instance
|
37
|
+
configure_instance_api_client()
|
38
|
+
when :user
|
39
|
+
configure_full_api_client(user, password)
|
40
|
+
else
|
41
|
+
raise "FATAL: ApiClient of #{type} not supported. You must specify either :user or :instance."
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# make connection to API v1.5 with 'instance' role
|
46
|
+
def configure_instance_api_client
|
47
|
+
options = {
|
48
|
+
:account_id => @account_id,
|
49
|
+
:instance_token => @instance_token,
|
50
|
+
:api_url => @api_url
|
51
|
+
}
|
52
|
+
instance_client = create_client(options)
|
53
|
+
instance_client.log(@log)
|
54
|
+
instance_client
|
55
|
+
end
|
56
|
+
|
57
|
+
# make connection to RightScale API v1.5 with a specific user's roles
|
58
|
+
def configure_full_api_client(user, password)
|
59
|
+
options = {:email => user, :password => password, :account_id => @account_id }
|
60
|
+
api_client = create_client(options)
|
61
|
+
api_client.log(@log)
|
62
|
+
api_client
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def parse_user_data
|
68
|
+
begin
|
69
|
+
require '/var/spool/cloud/user-data.rb'
|
70
|
+
rescue LoadError => e
|
71
|
+
puts "FATAL: not a RightScale managed VM, or you already cleaned up your user-data file."
|
72
|
+
exit 1
|
73
|
+
end
|
74
|
+
|
75
|
+
@api_token = ENV['RS_API_TOKEN']
|
76
|
+
raise 'RightScale API token environment variable RS_API_TOKEN is unset' unless @api_token
|
77
|
+
@account_id, @instance_token = @api_token.split /:/
|
78
|
+
@api_url = "https://#{ENV['RS_SERVER']}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_client(options)
|
82
|
+
RightApi::Client.new options
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
#
|
2
|
+
# Author: cary@rightscale.com
|
3
|
+
# Copyright 2014 RightScale, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
libdir = File.join(File.dirname(__FILE__), '..')
|
19
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
20
|
+
|
21
|
+
require 'trollop'
|
22
|
+
require 'api_client_15'
|
23
|
+
require 'image_bundle'
|
24
|
+
require 'mixins/command'
|
25
|
+
|
26
|
+
module ImageOptimize
|
27
|
+
|
28
|
+
class Optimizer
|
29
|
+
|
30
|
+
include ImageOptimize::Command
|
31
|
+
|
32
|
+
def run
|
33
|
+
parse_args
|
34
|
+
setup_logging
|
35
|
+
configure
|
36
|
+
|
37
|
+
# "cleaning" should wipe user-data and meta-data which will only allow this script
|
38
|
+
# to be run once. Default to false to so we can run this multiple times to make
|
39
|
+
# debugging more efficient.
|
40
|
+
# XXX: this probably should be done by the manager class
|
41
|
+
prepare_image if @args[:do_cleanup]
|
42
|
+
|
43
|
+
# generate unique image name and description for our image
|
44
|
+
name = unique_name(@args[:image_prefix])
|
45
|
+
description = @args[:image_description]
|
46
|
+
|
47
|
+
# snapshot and register new image
|
48
|
+
@log.info "Snapshot instance..."
|
49
|
+
@image_util.snapshot_instance(name, description)
|
50
|
+
@log.info "Register image..."
|
51
|
+
@image_util.register_image(name, description)
|
52
|
+
@log.info "Add image to next instance..."
|
53
|
+
@image_util.add_image_to_next_instance
|
54
|
+
@log.info "SUCCESS!"
|
55
|
+
end
|
56
|
+
|
57
|
+
def configure
|
58
|
+
|
59
|
+
@log.debug("Config Parameters: #{@args}")
|
60
|
+
|
61
|
+
# check for AWS credentials set
|
62
|
+
raise 'Environment variable AWS_SECRET_KEY must be set' unless @args[:aws_secret_key]
|
63
|
+
raise 'Environment variable AWS_ACCESS_KEY must be set' unless @args[:aws_access_key]
|
64
|
+
|
65
|
+
# XXX: The fact that we're using two API clients should be hidden
|
66
|
+
# inside a RightScale 'manager' class.
|
67
|
+
api_helper = RightScale::ApiClient15.new
|
68
|
+
api_helper.log(@log)
|
69
|
+
@instance_client = api_helper.get_client(:instance)
|
70
|
+
@api_client = api_helper.get_client(:user, @args[:api_user], @args[:api_password])
|
71
|
+
|
72
|
+
if @args[:aws_image_type] == "EBS" # XXX: use an image bundle factory instead of if-else
|
73
|
+
@log.debug("Creating ImageBundleEc2EBS object")
|
74
|
+
@image_util =
|
75
|
+
ImageBundleEc2EBS.new(
|
76
|
+
@instance_client, # XXX: instead of passing two api handles, just pass a manager class
|
77
|
+
@api_client,
|
78
|
+
@args[:aws_access_key],
|
79
|
+
@args[:aws_secret_key],
|
80
|
+
@args[:aws_kernel_id]
|
81
|
+
)
|
82
|
+
else
|
83
|
+
@log.debug("Creating ImageBundleEc2S3 object")
|
84
|
+
|
85
|
+
# check for credentials set in environment
|
86
|
+
raise 'Environment variable AWS_S3_IMAGE_BUCKET must be set' unless @args[:aws_s3_image_bucket]
|
87
|
+
raise 'Environment variable AWS_ACCOUNT_NUMBER must be set' unless @args[:aws_account_number]
|
88
|
+
|
89
|
+
@image_util =
|
90
|
+
ImageBundleEc2S3.new(
|
91
|
+
@instance_client,
|
92
|
+
@api_client,
|
93
|
+
@args[:aws_access_key],
|
94
|
+
@args[:aws_secret_key],
|
95
|
+
@args[:aws_account_number],
|
96
|
+
@args[:aws_s3_key_path],
|
97
|
+
@args[:aws_s3_cert_path],
|
98
|
+
@args[:aws_s3_image_bucket],
|
99
|
+
@args[:aws_s3_bundle_directory],
|
100
|
+
@args[:aws_s3_bundle_no_filter],
|
101
|
+
@args[:aws_kernel_id]
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
@image_util.log(@log)
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
def parse_args
|
110
|
+
version = File.open("VERSION", "r") { |f| f.read }
|
111
|
+
|
112
|
+
@args = Trollop::options do
|
113
|
+
version "image_optimize #{version} (c) 2014 RightScale, Inc."
|
114
|
+
banner <<-EOS
|
115
|
+
|
116
|
+
Bundle a running VM into a new image that will be used on next launch
|
117
|
+
|
118
|
+
Usage:
|
119
|
+
image_optimize [options]
|
120
|
+
where [options] are:
|
121
|
+
EOS
|
122
|
+
opt :verbose, "If set will enable debug logging. WARNING: will write ec2 creds to log if set!!",
|
123
|
+
:long => "--verbose", :default => false
|
124
|
+
|
125
|
+
opt :image_prefix, "Prefix to add to the optimized image name. Helps when searching for your optimized images.",
|
126
|
+
:default => "optimized-image", :long => "--prefix", :type => String
|
127
|
+
opt :image_description, "Description to add to optimized images",
|
128
|
+
:default => "Cached image", :long => "--description", :type => String
|
129
|
+
|
130
|
+
# Mangement platform API Creds
|
131
|
+
opt :api_user, "RightScale Dashboard User email. Not needed if API_USER_EMAIL environment variable is set.",
|
132
|
+
:default => ENV['API_USER_EMAIL'], :long => "--api-user", :short => "-u", :type => String
|
133
|
+
opt :api_password, "RightScale Dashboard User email. Not needed if API_USER_PASSWORD environment variable is set.",
|
134
|
+
:default => ENV['API_USER_PASSWORD'], :long => "--api-password", :short => "-p", :type => String
|
135
|
+
opt :do_cleanup, "Don't do any cleanup on VM before snapshotting. Useful for debugging.", :long => "--cleanup", :default => true
|
136
|
+
|
137
|
+
# EC2 Creds
|
138
|
+
opt :aws_access_key, "EC2 Account Access Key. Not needed if AWS_ACCESS_KEY environment variable is set.",
|
139
|
+
:default => ENV['AWS_ACCESS_KEY'], :long => "--aws-access-key", :short => "-k"
|
140
|
+
opt :aws_secret_key, "EC2 Account Secret. Not needed if AWS_SECRET_KEY environment variable is set.",
|
141
|
+
:default => ENV['AWS_SECRET_KEY'], :long => "--aws-secret-key", :short => "-s"
|
142
|
+
opt :aws_account_number, "EC2 Account ID. Not needed if AWS_ACCOUNT_NUMBER environment variable is set. Required for S3 images only.",
|
143
|
+
:default => ENV['AWS_ACCOUNT_NUMBER'], :long => "--aws-account-number"
|
144
|
+
|
145
|
+
# EC2 Image type
|
146
|
+
opt :aws_image_type, "The type of image to create from this VM. Must be either 'EBS' or 'S3'. ",
|
147
|
+
:default => 'EBS', :long => "--aws-image-type", :type => String
|
148
|
+
opt :aws_kernel_id, "Kernel to use instead of what the VM is running. i.e. 'aki-fc8f11cc'. For a current list of IDs see http://goo.gl/dOS0mB.",
|
149
|
+
:default => nil, :long => "--aws-kernel-id", :type => String
|
150
|
+
|
151
|
+
# EC2 Instance Store Parameters
|
152
|
+
opt :aws_s3_key_path, "location to file containing EC2 account key. S3 images only.",
|
153
|
+
:default => '/tmp/certs/x509.key', :long => "--aws-s3-key-path"
|
154
|
+
opt :aws_s3_cert_path, "location to file containing EC2 account cert. S3 images only.",
|
155
|
+
:default => '/tmp/certs/x509.cert', :long => "--aws-s3-cert-path"
|
156
|
+
opt :aws_s3_image_bucket, "The bucket name for optimized S3 images (must be url safe). S3 images only",
|
157
|
+
:default => "optimized-images", :long => "--aws-s3-image-bucket"
|
158
|
+
opt :aws_s3_bundle_directory, "The local directory where the image bundle will be stored before uploading to S3. NOTE: this must have enough free space to hold the image bundle.",
|
159
|
+
:default => "/mnt/ephemeral/bundle", :long => "--aws-s3-bundle-directory"
|
160
|
+
opt :aws_s3_bundle_no_filter, "If set, will disable the default filtering used by the ec2-bundle-vol command. WARNING: setting this option could leave ssh keys or other secrets on your",
|
161
|
+
:default => false, :long => "--aws-s3-bundle-no-filter"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
# create an image name using prefix and VM name
|
168
|
+
#
|
169
|
+
# Returns: [String] image name
|
170
|
+
def unique_name(prefix)
|
171
|
+
image_name = "#{@instance_client.get_instance.name} #{Time.new.to_s}"
|
172
|
+
image_name = "#{prefix} #{image_name}" if prefix
|
173
|
+
image_name.gsub(/[^0-9A-Za-z.\-]/, '-') # sanitize it!
|
174
|
+
end
|
175
|
+
|
176
|
+
# clean image for snapshoting
|
177
|
+
# taken from http://cpenniman.blogspot.com/2012/09/cleaning-up-rightimage-before.html
|
178
|
+
def prepare_image
|
179
|
+
@log.info "Prepare image"
|
180
|
+
cmd = "rm -rf /var/spool/cloud /var/lib/rightscale/right_link/*.js ; rm -f /opt/rightscale/var/lib/monit/monit.state ; rm -f /opt/rightscale/var/run/monit.pid ; sync"
|
181
|
+
execute(cmd)
|
182
|
+
end
|
183
|
+
|
184
|
+
# configure logging
|
185
|
+
def setup_logging
|
186
|
+
@log = Logger.new(STDOUT)
|
187
|
+
@log.level = Logger::INFO
|
188
|
+
@log.level = Logger::DEBUG if @args[:verbose]
|
189
|
+
@log.formatter = proc do |serverity, time, progname, msg|
|
190
|
+
"#{msg}\n"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
end
|