image_optimize 1.0.0 → 1.0.1
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.
- 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
|