hawser 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf941e79bf69e2c5a377996a0b8bec222e65232a
4
- data.tar.gz: 3905483927606e26b00f4cade2fff9f6535d9f08
3
+ metadata.gz: f37eabe7ab5a93f7ac12ae94512c90d3d5f92b5b
4
+ data.tar.gz: 897451652af6a7277f9f993ea68edd25b51a1b08
5
5
  SHA512:
6
- metadata.gz: 0e82f6e9fa6e2ae598f2a8b4eac50893c41f5be524edc2a93e8cb92175b828ac03cc4011d49bf17cc3f5c8f019964c68dafbbc0259d44ff251a723fe57186329
7
- data.tar.gz: c8790b49b61e5863e12e5fa7527cb8dfb3431e16f17d52d88af884a647bff68988a52b7b33b7443d091c6f9fdb6c26c69153d5dc4da81d387f39b7d912fac42d
6
+ metadata.gz: b3a8730daffd3c68e99eb12e3d6d3db06e505fb5181bb993b5e72e146b85073c05e068a49b0c562280e6928b782826d799bf0e1e23d868dc4daa6af89d036acd
7
+ data.tar.gz: 6b08518ebf9b91e8a670d5106b63e395dc8f43f8169904452d6a4928d2fa795fff00da35eda1ec6ecb4975479b1a57b5a46952000f598f869101a92c292efa2b
@@ -9,6 +9,13 @@ module Hawser
9
9
 
10
10
  setting :region, "us-west-1"
11
11
 
12
+ setting :block_mappings, {
13
+ "ami" => "sda1",
14
+ "root" => "/dev/sda1",
15
+ "ephemeral0" => "sda2",
16
+ "swap" => "sda3"
17
+ }
18
+
12
19
  dir(:ephemeral_dir, "mnt",
13
20
  dir(:keyfile_dir, "keys",
14
21
  path(:private_key, "pk.pem"),
@@ -56,6 +63,10 @@ module Hawser
56
63
  bundle.options += ["-k", private_key.abspath ]
57
64
  bundle.options += ["-c", certificate_file.abspath ]
58
65
  bundle.options += ["--user", aws_account_id ]
66
+ bundle.options += ["--block-device-mapping", block_mappings.map do |name, dev|
67
+ "#{name}=#{dev}"
68
+ end.join(",")
69
+ ]
59
70
 
60
71
  bundle.options += ["--destination", ephemeral_dir.abspath ]
61
72
  bundle.options += ["--prefix", prefix ]
@@ -79,6 +90,12 @@ module Hawser
79
90
  register.options += ["--region", region]
80
91
  register.options += ["--aws-access-key", access_key]
81
92
  register.options += ["--aws-secret-key", secret_key]
93
+ }) &
94
+ (cmd("rm") {|rm|
95
+ rm.options = ["-rf", keyfile_dir.abspath]
96
+ }) &
97
+ (cmd("rm") {|rm|
98
+ rm.options = ["-f", File::join(ephemeral_dir.abspath, prefix || "no-such-file"), File::join(ephemeral_dir.abspath, prefix || "no-such-file") + ".part.*" ]
82
99
  })
83
100
  end
84
101
  end
@@ -2,6 +2,7 @@ require 'mattock'
2
2
  require 'hawser/credentialing'
3
3
  require 'hawser/baking'
4
4
  require 'hawser/servers'
5
+ require 'hawser/volumes'
5
6
 
6
7
  module Hawser
7
8
  # Represents a cluster of servers on AWS
@@ -47,12 +48,25 @@ module Hawser
47
48
  creds.credentials.proxy_settings_to(servers)
48
49
  end
49
50
 
51
+ Hawser::Volumes.new do |volumes|
52
+ copy_settings_to(volumes)
53
+ volumes.cluster_name = name
54
+ creds.copy_settings_to(volumes)
55
+ creds.credentials.proxy_settings_to(volumes)
56
+ end
57
+
50
58
  namespace :baking do
51
- task :bake => "credentials:establish"
59
+ task :copy_key => "credentials:establish"
60
+ task :copy_cert => "credentials:establish"
52
61
  end
53
62
 
54
63
  namespace :servers do
55
64
  task :list => "credentials:establish"
65
+ task :view => "credentials:establish"
66
+ end
67
+
68
+ namespace :volume do
69
+ task :clone => "credentials:establish"
56
70
  end
57
71
 
58
72
  desc "Make an AMI copy of the running instance at :target named :name"
@@ -72,10 +72,11 @@ module Hawser
72
72
 
73
73
  cert = OpenSSL::X509::Certificate.new
74
74
  cert.version = 2
75
- cert.serial = 2
75
+ cert.serial = OpenSSL::Random.random_bytes(16).each_byte.inject(0){|sum, byte| (sum << 8) + byte}
76
76
  cert.public_key = key.public_key
77
77
  cert.not_before = Time.now
78
78
  cert.not_after = cert.not_before + self.cert.lifetime.total_seconds
79
+ cert.sign(key, OpenSSL::Digest::SHA256.new)
79
80
 
80
81
  cert.to_pem
81
82
  end
@@ -126,12 +127,21 @@ module Hawser
126
127
  in_namespace do
127
128
  directory user_dir.abspath
128
129
 
129
- file signing_cert.abspath => signing_key.abspath do |task|
130
+ task :umask do
131
+ File::umask(0077)
132
+ end
133
+
134
+ file signing_cert.abspath => [:umask, signing_key.abspath] do |task|
135
+ require 'base64'
136
+
130
137
  key = File::read(signing_key.abspath)
131
- File.write(task.name, signing_cert_content(key))
138
+ cert_pem = signing_cert_content(key)
139
+ File.open(task.name, "wb") do |file|
140
+ file.print cert_pem
141
+ end
132
142
  end
133
143
 
134
- file signing_key.abspath do |task|
144
+ file signing_key.abspath => :umask do |task|
135
145
  File.write(task.name, signing_key_content)
136
146
  end
137
147
 
@@ -141,14 +151,16 @@ module Hawser
141
151
  end
142
152
  end
143
153
 
144
- task :store do
154
+ task :store => :umask do
145
155
  require 'yaml'
146
156
 
157
+ puts "Storing credentialing info at #{config_yaml.abspath}"
147
158
  File::open(config_yaml.abspath, "w") do |config|
148
159
  config.write YAML.dump(Hash[credentials.to_hash.map do |key,value|
149
160
  [key.to_s, value]
150
161
  end])
151
162
  end
163
+
152
164
  end
153
165
 
154
166
  task :iam => "get:access" do
@@ -160,9 +172,10 @@ module Hawser
160
172
  end
161
173
 
162
174
  namespace :get do
163
- task :access => :load do
175
+ task :access => [:umask, :load] do
164
176
  if credentials.access_key.nil? or credentials.secret_key.nil?
165
177
  load_from_csv(File.read(creds_csv.abspath))
178
+ puts "Loaded access key id and key secret from CSV at #{creds_csv.abspath}"
166
179
  end
167
180
  end
168
181
 
@@ -181,11 +194,12 @@ module Hawser
181
194
  namespace :set do
182
195
  task :password => :iam_user do
183
196
  unless credentials.password.nil?
197
+ puts "Setting login password"
184
198
  iam_user.login_policy.password = credentials.password
185
199
  end
186
200
  end
187
201
 
188
- task :certificate => [:iam_user, signing_cert.abspath, "get:certificate_id"] do
202
+ task :certificate => [:umask, :iam_user, signing_cert.abspath, "get:certificate_id"] do
189
203
  if !credentials.certificate_id.nil?
190
204
  begin
191
205
  iam_user.signing_certificates[credentials.certificate_id].contents
@@ -194,6 +208,7 @@ module Hawser
194
208
  end
195
209
  end
196
210
 
211
+ puts "Uploading signing certificate at #{signing_cert.abspath}"
197
212
  cert = iam_user.signing_certificates.upload(File::read(signing_cert.abspath))
198
213
  credentials.certificate_id = cert.id
199
214
  end
@@ -31,6 +31,30 @@ module Hawser
31
31
  "key_name" => instance.key_name }
32
32
  end))
33
33
  end
34
+
35
+ desc "View details for a server for #{cluster_name}"
36
+ task :view, [:id] do |task, args|
37
+ if args[:id].nil?
38
+ fail ":id is required"
39
+ end
40
+ require 'yaml'
41
+ ec2 = AWS::EC2.new(:region => region, :access_key_id => access_key, :secret_access_key => secret_key)
42
+
43
+ instance = ec2.instances.find do |inst|
44
+ inst.instance_id == args[:id]
45
+ end
46
+
47
+ if instance.nil?
48
+ fail "Couldn't find instance with id #{args[:id]} in #{ec2.instances.map{|inst| inst.instance_id}}"
49
+ end
50
+
51
+ require 'pp'
52
+ pp instance
53
+ pp instance.class.ancestors
54
+ puts instance.to_yaml
55
+ pp instance.block_device_mappings
56
+
57
+ end
34
58
  end
35
59
  end
36
60
  end
@@ -0,0 +1,102 @@
1
+ require 'mattock'
2
+ require 'aws-sdk'
3
+
4
+ module Hawser
5
+ class Volumes < Mattock::Tasklib
6
+ default_namespace :volume
7
+
8
+ setting :cluster_name
9
+ setting :access_key
10
+ setting :secret_key
11
+ setting :region, "us-west-1"
12
+
13
+ def define
14
+ in_namespace do
15
+ desc "Clone <from_dev> on <from_instance> to <to_dev> on <to_instance>"
16
+ task :clone, [:from_instance, :from_dev, :to_instance, :to_dev] do |task, args|
17
+ missing = [:from_instance, :from_dev, :to_instance].find_all do |key|
18
+ args[key].nil?
19
+ end
20
+
21
+ unless missing.empty?
22
+ fail "Missing required arguments: #{missing.inspect}"
23
+ end
24
+
25
+ to_dev = args[:to_dev] || args[:from_dev]
26
+
27
+ ec2 = AWS::EC2.new(:region => region, :access_key_id => access_key, :secret_access_key => secret_key)
28
+
29
+ instances = ec2.instances
30
+ from_instance = instances.find do |inst|
31
+ inst.instance_id == args[:from_instance]
32
+ end
33
+
34
+ to_instance = instances.find do |inst|
35
+ inst.instance_id == args[:to_instance]
36
+ end
37
+
38
+ missing_instances = []
39
+ if from_instance.nil?
40
+ missing_instances << "Missing instance for #{args[:from_instance].inspect}"
41
+ end
42
+ if to_instance.nil?
43
+ missing_instances << "Missing instance for #{args[:to_instance].inspect}"
44
+ end
45
+ unless missing_instances.empty?
46
+ fail "Missing instances: #{missing_instances.join.inspect}"
47
+ end
48
+
49
+ require 'pp'
50
+ from_device = from_instance.block_devices.find do |dev|
51
+ dev[:device_name] == args[:from_dev]
52
+ end
53
+ unless from_device
54
+ fail "No device mapped to #{args[:from_instance]} on #{args[:from_dev]}"
55
+ end
56
+
57
+ if to_instance.block_devices.any?{|dev| dev[:device_name] == to_dev}
58
+ fail "A device is already mapped to #{args[:to_instance]} on #{to_dev}"
59
+ end
60
+
61
+ from_volume = ec2.volumes.find do |vol|
62
+ from_device[:ebs][:volume_id] == vol.id
63
+ end
64
+
65
+ unless from_volume
66
+ fail "No volume matches #{from_device[:ebs][:volume_id].inspect}"
67
+ end
68
+
69
+ snapshot_desc = from_volume.tags["Name"] || "From #{args[:from_instance]}:#{args[:from_dev]}"
70
+
71
+ intermediate_snapshot = from_volume.create_snapshot(snapshot_desc)
72
+ at_exit{ intermediate_snapshot.delete }
73
+
74
+ wait_for_status("intermediate snapshot", intermediate_snapshot, :completed)
75
+
76
+ new_volume = intermediate_snapshot.create_volume(to_instance.availability_zone)
77
+
78
+ wait_for_status("volume creation", new_volume, :available)
79
+
80
+ new_volume.attach_to(to_instance, to_dev)
81
+
82
+ wait_for_status("volume attachment", new_volume, :in_use)
83
+
84
+ puts "Done"
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ def wait_for_status(name, resource, goal)
91
+ puts "Waiting for #{name}"
92
+ until [goal, :error].include?(resource.status)
93
+ print "."
94
+ sleep 1
95
+ end
96
+
97
+ puts "\n #{name} complete. Status: #{resource.status.inspect}"
98
+ fail if resource.status != goal
99
+ end
100
+
101
+ end
102
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hawser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Judson Lester
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-22 00:00:00.000000000 Z
11
+ date: 2015-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>'
17
+ - - <
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '2.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>'
24
+ - - <
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mattock
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,7 @@ files:
52
52
  - lib/hawser/servers.rb
53
53
  - lib/hawser/baking-command.rb
54
54
  - lib/hawser/baking.rb
55
+ - lib/hawser/volumes.rb
55
56
  - spec/hawser_spec.rb
56
57
  - spec_help/gem_test_suite.rb
57
58
  homepage: http://nyarly.github.com/hawser
@@ -64,7 +65,7 @@ rdoc_options:
64
65
  - --main
65
66
  - doc/README
66
67
  - --title
67
- - hawser-0.1.1 Documentation
68
+ - hawser-0.2.0 Documentation
68
69
  require_paths:
69
70
  - lib/
70
71
  required_ruby_version: !ruby/object:Gem::Requirement