cluster 0.5.33
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/Rakefile +69 -0
- data/VERSION +1 -0
- data/bin/cluster +14 -0
- data/bin/ec2-consistent-snapshot +676 -0
- data/bin/periodic.sh +19 -0
- data/examples/cacerts.pem +19 -0
- data/examples/credentials.yml +24 -0
- data/examples/monitor.god +88 -0
- data/examples/users.sh +42 -0
- data/lib/cluster.rb +267 -0
- data/lib/cluster/cli.rb +206 -0
- data/lib/cluster/configuration.rb +52 -0
- data/lib/cluster/infrastructure.rb +160 -0
- data/lib/cluster/infrastructures/amazon.rb +568 -0
- data/lib/cluster/infrastructures/amazon_instance.rb +270 -0
- data/lib/cluster/infrastructures/amazon_release.rb +63 -0
- data/lib/cluster/instance.rb +97 -0
- data/lib/cluster/release.rb +30 -0
- data/lib/cluster/version.rb +25 -0
- data/lib/ext/array.rb +13 -0
- data/lib/ext/cluster_extensions.rb +13 -0
- metadata +206 -0
data/bin/periodic.sh
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# This will run periodically to do appropriate backups and cleanups.
|
3
|
+
# run as a crontab so the environment is minimal
|
4
|
+
|
5
|
+
export GEM_PATH=$(gem env gempath)
|
6
|
+
export CREDENTIALS=${HOME}/.cluster/credentials.yml
|
7
|
+
|
8
|
+
mysql_user=
|
9
|
+
mysql_host=$(cluster service -d database)
|
10
|
+
mysql_password=
|
11
|
+
aws_secret=""
|
12
|
+
aws_key=""
|
13
|
+
region=""
|
14
|
+
volume=""
|
15
|
+
mount=""
|
16
|
+
|
17
|
+
cluster period
|
18
|
+
|
19
|
+
sudo ec2-consistent-snapshot --aws-access-key-id ${aws_key} --aws-secret-access-key ${aws_secret} --mysql-user ${mysql_user} --mysql-password ${mysql_password} --mysql-host ${mysql_host} --xfs-filesystem ${mount} --region ${region} ${volume}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
|
3
|
+
FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
|
4
|
+
VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
|
5
|
+
biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
|
6
|
+
dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
|
7
|
+
MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
|
8
|
+
MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
|
9
|
+
A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
|
10
|
+
b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
|
11
|
+
cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
|
12
|
+
bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
|
13
|
+
VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
|
14
|
+
ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
|
15
|
+
uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
|
16
|
+
9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
|
17
|
+
hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
|
18
|
+
pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
|
19
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,24 @@
|
|
1
|
+
amazon:
|
2
|
+
user: 91*********
|
3
|
+
key: AKI**********
|
4
|
+
secret: U***************************
|
5
|
+
|
6
|
+
monitor:
|
7
|
+
email:
|
8
|
+
address: smtp.gmail.com
|
9
|
+
port: 587
|
10
|
+
domain: ingamersports.com
|
11
|
+
authentication: plain
|
12
|
+
user_name: dog@score345.com
|
13
|
+
password: *******
|
14
|
+
messages:
|
15
|
+
from: dog@ingamersports.com
|
16
|
+
contacts:
|
17
|
+
- name: alerts
|
18
|
+
email: alert@ingamersports.com
|
19
|
+
- name: panic
|
20
|
+
email: panic@ingamersports.com
|
21
|
+
group: emergency
|
22
|
+
- name: simon
|
23
|
+
email: sdeboer@ingamersports.com
|
24
|
+
group: person
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/bin/env god -c
|
2
|
+
require 'rubygems'
|
3
|
+
require 'tlsmail'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'cluster'
|
6
|
+
require 'cluster/infrastructures/amazon'
|
7
|
+
|
8
|
+
Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
|
9
|
+
|
10
|
+
CREDENTIALS = ENV['CREDENTIALS'] || File.join(ENV['HOME'], '.cluster', 'credentials.yml')
|
11
|
+
|
12
|
+
credentials_file = File.expand_path(CREDENTIALS)
|
13
|
+
|
14
|
+
unless File.exists?(credentials_file)
|
15
|
+
$stderr.puts "Cannot find credentials for cluster : #{credentials_file} !"
|
16
|
+
exit 2
|
17
|
+
end
|
18
|
+
MONITOR_PATH = File.join File.dirname(credentials_file), 'services.d'
|
19
|
+
|
20
|
+
Cluster::Configuration[:credentials_file] = credentials_file
|
21
|
+
CLUSTER = Cluster.new(Amazon.new)
|
22
|
+
|
23
|
+
class UserService < God::Behavior
|
24
|
+
def before_start
|
25
|
+
service = self.watch.name[/^(\w+)-/, 1]
|
26
|
+
users_file = File.join(MONITOR_PATH, service, 'users.sh')
|
27
|
+
unless File.exists? users_file
|
28
|
+
FileUtils.mkdir_p File.dirname users_file
|
29
|
+
CLUSTER.retrieve service, 'users.sh', users_file
|
30
|
+
end
|
31
|
+
|
32
|
+
system(users_file) if File.exists? users_file
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class ProjectService < God::Behavior
|
37
|
+
def before_start
|
38
|
+
service = self.watch.name[/^(\w+)-/, 1]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
creds = YAML::load_file credentials_file
|
43
|
+
|
44
|
+
if creds.include? 'monitor'
|
45
|
+
moni = creds['monitor']
|
46
|
+
email = moni['email'].keys.inject({}) {|m, k|
|
47
|
+
m.merge k.to_sym => moni['email'][k]
|
48
|
+
}
|
49
|
+
God::Contacts::Email.server_settings = email
|
50
|
+
God::Contacts::Email.message_settings = {
|
51
|
+
:from => moni['messages']['from']
|
52
|
+
}
|
53
|
+
|
54
|
+
if moni.include? 'contacts'
|
55
|
+
for contact in moni['contacts']
|
56
|
+
God.contact(:email) {|c|
|
57
|
+
c.name = contact['name']
|
58
|
+
c.email = contact['email']
|
59
|
+
contact['group'] and (c.group = contact['group'])
|
60
|
+
}
|
61
|
+
end
|
62
|
+
else
|
63
|
+
God.contact(:email) {|c|
|
64
|
+
c.name = 'system notification'
|
65
|
+
c.email = moni['messages']['from']
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
CLUSTER.instance_state('configuring')
|
71
|
+
|
72
|
+
for service in CLUSTER.current('services')
|
73
|
+
monitor_file = File.join MONITOR_PATH, service, "config.god"
|
74
|
+
FileUtils.mkdir_p File.dirname(monitor_file)
|
75
|
+
begin
|
76
|
+
CLUSTER.retrieve service, 'config.god', monitor_file
|
77
|
+
rescue => err
|
78
|
+
applog(nil, :warn, "Service of #{service} does not appear to have a monitor configuration. Skipping!")
|
79
|
+
next
|
80
|
+
end
|
81
|
+
|
82
|
+
if File.readable? monitor_file
|
83
|
+
applog(nil, :info, "Loading monitor file #{monitor_file}")
|
84
|
+
load monitor_file
|
85
|
+
else
|
86
|
+
applog(nil, :warn, "Cannot find a monitor file for #{monitor_file}")
|
87
|
+
end
|
88
|
+
end
|
data/examples/users.sh
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
if ! id staging 2>/dev/null 1>&2; then
|
4
|
+
adduser --disabled-password --gecos 'staging' staging
|
5
|
+
mkdir -m 700 ~staging/.ssh
|
6
|
+
touch ~staging/.ssh/authorized_keys
|
7
|
+
chmod 600 ~staging/.ssh/authorized_keys
|
8
|
+
touch ~staging/.ssh/config
|
9
|
+
chmod 600 ~staging/.ssh/config
|
10
|
+
|
11
|
+
cat >>~staging/.ssh/authorized_keys <<END_OF_KEYS
|
12
|
+
ssh-dss AAAAB3NzaC1kc3MAAACBANcFLeySRpmVji+g9KcHBaedFE5SOLgkSQIKbeVjOwzGC75AIM5gY6gjOu0Kj4BYhlxUwOWkOEYgZwqu15qxtKPCnYQST3jqQnbfwN8UOC4y7XH/4G0gdOD9taFx4PpW0H+zvYs7smBb1qG8NnlUH1tyCGdNNmZLxn2b84R5pDcVAAAAFQDqV2zGPugaRR7gslhxyxrZnIpE9QAAAIAtEViFMBq8h4TXXbdeYR3EhR+zcUHzRz/yB3N7mdo8C1a5apHAnzwX7RPzvkskThU2Idj3ZxUyrTbd5WpBfk/OIwF+hvM3/Uw6XJLNaDSTd0t0HOJxE+SJuHwfOwNtI+J2IXwckUJ2laOTwjOc0YzIR1Gnf50gcz67R07H4qidtQAAAIANQsT7jT68TemlxBjjK22YDRxdRC5M2VuTAT6dDp9JL7KB6B1b3kU7EjiG9gk9oDUGWQiE5sEtHaFjgeViSwQhtaQ/Rqx8EmNG5W9lNgVcWtPmxqMJtOaaNggE+znE1xanY+fDtLqbAkbExZ8vypyUuMXvsgl7AiSSEMnpmX1Itw== simon@s345
|
13
|
+
ssh-dss AAAAB3NzaC1kc3MAAACBAIxHXUznZLryPsnK0YCa7W4HM3wSqpCV8MwIBYd4kl/qQzC2VlyX0mFhVFC3esLWyyWEAFcKyI3FlzI70Z4ppnukyL/2MonVTqto3RPoTQs8Ty3y10MYo+9UE65U6Rv2yHfx551vobJgHgVS7tmupCcemZYscgFCeUMgLOz+5tylAAAAFQC9NTxN10PfjndbLDaPYrpC3h8g9wAAAIBnq0vCE9FqjukltP85M5qiawS5sEXArB0HRP4MDpwk4xDdrpiEwa2qYSOiwN1brsxMGrVHe3HetPeApmZZV5vysV1sLp3CQAlGHoWJ3GjOR3lDYpTymlbZOzd62mKp7FxPVtNszbDiABJckTLUV95TM2OB2hn/mWqpzwJBh9GBrAAAAIAmFDbo3aCg3WcDFnBzI72aHBQ4532xEMrlASABJ9FwkNPCtr2VZRLR4vxo9Oyn21+z4SmFocJN0DcKgj1APeS8en/frAFG/UJr/4KdV/LAnTBz8qd6QnbxdUYxizVoYKI1Pl76axbPQCVe+dthfn0x19quOMc/ofHA7I0GGIojJw== nick@Sparta-MB.local
|
14
|
+
ssh-dss AAAAB3NzaC1kc3MAAACBAO/mj7W3wUuDAhvicx+C2MkAFJGFZvaPrBA+nbFbK240HDZcmS8sA9Ww3VwivKzQ4CwrpdMY3dPg0TM9H2USQvfMsis4bStDwLy4CFIvBEGoviVVdu8gBzVN+YGajhv7yZqJ9cpOSnUXUzCBh4ddhLtni4IQ2lEZyKdlUzmA77pZAAAAFQDSdiFXpCu3CrAm0zivwA68DcDj5wAAAIEA557V4w7vNgmZvkb3hnQui5IkVTpN+b2PKCzvA9clbJQvKBpivS7k5jpx+GeoAYA+pYNLppMf9zpyPLrJjJhJ3Y3qS3p5iFCed2aJRwxhd5lYIyEedZ2uW6tchVRPoXkT1/tmXBKUNnue8YHslhqXOy8nHyHd7dH7BXLblnQknRcAAACBANzpDp5oXEG7w40tCYd7dtJfDLT8cIXyA75yX2MtkHjpBylT+lP/c1P9pmPytEtBfoQCvwFKjVA7fVGTkF1QfMVzcJsB1wh6jUyS287JtbS4D2O/yEP6FioG5Qva8GdJ29Oy49+LIHgamc93ZaJPub+wvFYivNzQsomjdXtiNRNA olpc@xo-10-F8-44.localdomain
|
15
|
+
ssh-dss AAAAB3NzaC1kc3MAAACBAOC9i08N/CoZO9I4kXv8LFSkReglZw9gmOqK72E/IpijLZkd2oh0wyV98S+8lYZR0OPmK6B4vbPIarBsZiPfOe2EMGxsuYjwD3X3S2hIM/1zrvk+WMzf6UADxmCwWzC6bYa1aBH59ba9ojolsBuou6yOxm3boYmZYbnMCLUzm/eLAAAAFQCHNIOpZTKG0chczg+5T3WJ4Q5JAwAAAIA2/VIk8pST/ynuXuu82Z9ZsR9ZJHICYfYi2EqLA6qJUxSB8MjvF9BQGYgX+UCs96uFme8wPJMBU74c7mZlcHvtlgc+1rMQUTZhJ820b/eg2gcPKGYikWj8y3wT0TDoWemMWAaFprvgrPLhHYuVMUKKzI9VNTeKDD7NC1xMsd9pOgAAAIBT14VMwBZjaq0oJSDxzy7bgf5Tragy9yhs7ZgQ0QTpMTFrkO/YvbsCLeXbsRcq904EMcB5glOHXONppn5skwWwBCFtjpjL9WLaeCnhpCxFC+D89GyR7T3Jlvj/Wa2tkuCSFJLBc64kK+pTmDseRLBbhazJazn3oUrNuEFtazzZCw== simon@secondary
|
16
|
+
ssh-dss AAAAB3NzaC1kc3MAAACBALlZtmMckFufyVq+It10p4pC65NJCRdDpRrf1uIoVXvz1ZSlsm/f0jhatuNPpwnSQoRpvlWetiS5mzGJ3ze8aReqHHe9CZvDCpVy33cwyRhCZf7ndyGh1qa9ZA0YMHNVdVs03SpNr7Fzc3muGcKX3BiiOZz+6mtbaQW0X1p/VHpLAAAAFQC8AuBVqCRJKgBMHDHb0nxQAyHbRQAAAIEAgQJvHZ3Db3yVy99goeIJw/3lysVemaddIdPuJj/AdxRwkDeuZIxxtOUne/qjXr7hmu48EyXLVg/jsNivKarLI6CXZAk5JbxkgLN+8y0Ckzcd48KhSGpZsbTBtjV29UFH9aiMVOUTbL59603HNa3ucH2lCLhllBf+ameZZp+EFYMAAACARZwlCuPobEAk7wOxWzGQcaRvmSDSbIKexMeUBgZBZeYjp5Bxld6e7x/j3GBQEkzmxqf08zP6LpglDoNR3KuY2TEWhAS3H1KdT4GibNSNpY4y2Pl2K/GjUWC6wMmVcFFBCz/jJorttMSI1G+OVcy+Vdw42HyQ5Z2QtuoVA2MQ5IQ= staging@domU-12-31-39-0E-C8-82
|
17
|
+
END_OF_KEYS
|
18
|
+
cat >>~staging/.ssh/config <<END_OF_CONFIG
|
19
|
+
Host web
|
20
|
+
HostName domU-12-31-39-00-64-E4.compute-1.internal
|
21
|
+
User app
|
22
|
+
Host webu
|
23
|
+
HostName domU-12-31-39-00-64-E4.compute-1.internal
|
24
|
+
User ubuntu
|
25
|
+
Host *.compute-1.internal
|
26
|
+
ForwardAgent yes
|
27
|
+
END_OF_CONFIG
|
28
|
+
|
29
|
+
chown -R staging:staging ~staging/.ssh
|
30
|
+
fi
|
31
|
+
|
32
|
+
if ! id app 2>/dev/null 1>&2; then
|
33
|
+
adduser --disabled-password --gecos 'app' app
|
34
|
+
mkdir -m 700 ~app/.ssh
|
35
|
+
touch ~app/.ssh/authorized_keys
|
36
|
+
chmod 600 ~app/.ssh/authorized_keys
|
37
|
+
|
38
|
+
cat >>~app/.ssh/authorized_keys <<END_OF_KEYS
|
39
|
+
ssh-dss AAAAB3NzaC1kc3MAAACBALlZtmMckFufyVq+It10p4pC65NJCRdDpRrf1uIoVXvz1ZSlsm/f0jhatuNPpwnSQoRpvlWetiS5mzGJ3ze8aReqHHe9CZvDCpVy33cwyRhCZf7ndyGh1qa9ZA0YMHNVdVs03SpNr7Fzc3muGcKX3BiiOZz+6mtbaQW0X1p/VHpLAAAAFQC8AuBVqCRJKgBMHDHb0nxQAyHbRQAAAIEAgQJvHZ3Db3yVy99goeIJw/3lysVemaddIdPuJj/AdxRwkDeuZIxxtOUne/qjXr7hmu48EyXLVg/jsNivKarLI6CXZAk5JbxkgLN+8y0Ckzcd48KhSGpZsbTBtjV29UFH9aiMVOUTbL59603HNa3ucH2lCLhllBf+ameZZp+EFYMAAACARZwlCuPobEAk7wOxWzGQcaRvmSDSbIKexMeUBgZBZeYjp5Bxld6e7x/j3GBQEkzmxqf08zP6LpglDoNR3KuY2TEWhAS3H1KdT4GibNSNpY4y2Pl2K/GjUWC6wMmVcFFBCz/jJorttMSI1G+OVcy+Vdw42HyQ5Z2QtuoVA2MQ5IQ= staging@domU-12-31-39-0E-C8-82
|
40
|
+
END_OF_KEYS
|
41
|
+
chown -R app:app ~app/.ssh
|
42
|
+
fi
|
data/lib/cluster.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
%w(configuration version infrastructure instance release).each {|l| require File.join('cluster', l) }
|
2
|
+
|
3
|
+
class Cluster
|
4
|
+
def security(*groups)
|
5
|
+
groups << 'access' if groups.empty?
|
6
|
+
@sub.security(groups)
|
7
|
+
end
|
8
|
+
|
9
|
+
def cost(*sizes)
|
10
|
+
@sub.cost(sizes)
|
11
|
+
end
|
12
|
+
|
13
|
+
def period(*args)
|
14
|
+
@sub.period(args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def revoke(*ips)
|
18
|
+
if ips.empty?
|
19
|
+
current_ip = ''
|
20
|
+
require 'open-uri'
|
21
|
+
open('http://checkip.dyndns.com').each do |line|
|
22
|
+
current_ip = $1 and break if line =~ /IP Address: ([\d\.]+)</
|
23
|
+
end
|
24
|
+
ips << "#{current_ip}/32"
|
25
|
+
end
|
26
|
+
@sub.revoke(ips)
|
27
|
+
end
|
28
|
+
|
29
|
+
def authorize(*ips)
|
30
|
+
if ips.empty?
|
31
|
+
current_ip = ''
|
32
|
+
require 'open-uri'
|
33
|
+
open('http://checkip.dyndns.com').each do |line|
|
34
|
+
current_ip = $1 and break if line =~ /IP Address: ([\d\.]+)</
|
35
|
+
end
|
36
|
+
ips << "#{current_ip}/32"
|
37
|
+
end
|
38
|
+
@sub.authorize(ips)
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(infrastructure)
|
42
|
+
self.class.set_credentials_file
|
43
|
+
infrastructure.configure
|
44
|
+
@sub = infrastructure
|
45
|
+
end
|
46
|
+
|
47
|
+
def machine(groups = [])
|
48
|
+
res = machines(groups)
|
49
|
+
res.empty? ? nil : res.first
|
50
|
+
end
|
51
|
+
|
52
|
+
def machines(groups = [])
|
53
|
+
@sub.machines(groups)
|
54
|
+
end
|
55
|
+
alias :instances :machines
|
56
|
+
|
57
|
+
def service(roles)
|
58
|
+
res = services(roles)
|
59
|
+
res.empty? ? nil : res.first
|
60
|
+
end
|
61
|
+
|
62
|
+
def services(roles = [])
|
63
|
+
@sub.services(roles)
|
64
|
+
end
|
65
|
+
|
66
|
+
def labeled(name)
|
67
|
+
@sub.instances.select {|i| i.identified_by? name}
|
68
|
+
end
|
69
|
+
|
70
|
+
def release(*params)
|
71
|
+
klass = @sub.release_class
|
72
|
+
env, tag = params
|
73
|
+
if tag
|
74
|
+
klass.find(env, tag) or klass.create(:environment => env, :tag => tag)
|
75
|
+
elsif env
|
76
|
+
klass.current(env)
|
77
|
+
else
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_credentials
|
83
|
+
{'credentials' => nil}
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_file_store(name)
|
87
|
+
@sub.create_file_store(name)
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_data_store(name)
|
91
|
+
@sub.create_data_store(name)
|
92
|
+
end
|
93
|
+
|
94
|
+
def start(machine_size, *services)
|
95
|
+
size = machine_size.to_s.strip.downcase
|
96
|
+
unless @sub.class.machine_sizes.include? size
|
97
|
+
msg = "#{Cluster::NAME} needs to have a size from: #{@sub.class.machine_sizes.join(', ')}"
|
98
|
+
puts msg
|
99
|
+
raise msg
|
100
|
+
end
|
101
|
+
# FIXME need a way to pass through a number argument
|
102
|
+
number ||= 1
|
103
|
+
|
104
|
+
services = services.map {|s|
|
105
|
+
s.split(',')
|
106
|
+
}.flatten
|
107
|
+
|
108
|
+
# This may not be necessary, but might as well make sure they are
|
109
|
+
# up to date any time that we are starting a new instance.
|
110
|
+
self.save_credentials
|
111
|
+
|
112
|
+
begin
|
113
|
+
number.times.map do |n|
|
114
|
+
@sub.new_instance(size, services)
|
115
|
+
end
|
116
|
+
rescue => err
|
117
|
+
puts "#{Cluster::NAME} cannot start new instance: #{err.message}\n\t#{err.backtrace.join("\n\t")}"
|
118
|
+
exit 2
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def update_image_file(filename)
|
123
|
+
input = File.open(filename)
|
124
|
+
@sub.save_images(input)
|
125
|
+
end
|
126
|
+
|
127
|
+
def current(*params)
|
128
|
+
unless @sub.in_cluster?
|
129
|
+
puts "#{Cluster::NAME} says that we aren't in the cluster?"
|
130
|
+
exit 2
|
131
|
+
end
|
132
|
+
|
133
|
+
unless params.length > 0
|
134
|
+
puts "#{Cluster::NAME} current needs to know what to do?\n\t* services\n\t* name (|| dns)\n\t* ip\n\t* enable\n\t* disable"
|
135
|
+
exit 2
|
136
|
+
end
|
137
|
+
|
138
|
+
cmd = params.shift
|
139
|
+
|
140
|
+
case cmd.downcase
|
141
|
+
when 'services'
|
142
|
+
@sub.current_instance.services
|
143
|
+
when /^(n|dn)/
|
144
|
+
@sub.current_instance.dns
|
145
|
+
when /^i/
|
146
|
+
@sub.current_instance.ip
|
147
|
+
when /^e/
|
148
|
+
@sub.alter_instances!(@sub.current_instance) {|i| i.enable *params }
|
149
|
+
when /^di/
|
150
|
+
@sub.alter_instances!(@sub.current_instance) {|i| i.disable *params }
|
151
|
+
when /^s/
|
152
|
+
@sub.alter_instances!(@sub.current_instance) {|i| i.set_state *params }
|
153
|
+
else
|
154
|
+
puts "${Cluster::NAME} current did not understand '#{params.join(' ')}'"
|
155
|
+
exit 1
|
156
|
+
end
|
157
|
+
end
|
158
|
+
alias :instance :current
|
159
|
+
|
160
|
+
def instance_state(state)
|
161
|
+
@sub.current_instance.set_state(state)
|
162
|
+
end
|
163
|
+
|
164
|
+
def store(service, key, filename = nil)
|
165
|
+
full_key = File.join service, key
|
166
|
+
file = if filename and File.readable? filename
|
167
|
+
File.open(filename, 'r')
|
168
|
+
elsif File.readable? full_key
|
169
|
+
File.open(full_key, 'r')
|
170
|
+
elsif File.readable? File.basename(full_key)
|
171
|
+
File.open(File.basename(full_key))
|
172
|
+
else
|
173
|
+
puts "#{Cluster::NAME} cannot open a file for storage"
|
174
|
+
exit 2
|
175
|
+
end
|
176
|
+
@sub.store full_key, file
|
177
|
+
end
|
178
|
+
|
179
|
+
def retrieve(service, key, output = nil)
|
180
|
+
res = @sub.retrieve File.join(service, key)
|
181
|
+
if output
|
182
|
+
begin
|
183
|
+
File.open(output, 'w') {|f|
|
184
|
+
f.write res
|
185
|
+
}
|
186
|
+
rescue => err
|
187
|
+
puts "#{Cluster::NAME} cannot open #{output} for writing."
|
188
|
+
exit 2
|
189
|
+
end
|
190
|
+
else
|
191
|
+
res
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def save_credentials(location = nil)
|
196
|
+
creds = if Cluster::Configuration.credentials?
|
197
|
+
File.open(Cluster::Configuration[:credentials_file])
|
198
|
+
else
|
199
|
+
cx = @sub.to_credentials.merge to_credentials
|
200
|
+
StringIO.new(cx.to_yaml)
|
201
|
+
end
|
202
|
+
@sub.save_credentials(creds, location)
|
203
|
+
end
|
204
|
+
|
205
|
+
def save_monitor(filename, key = nil)
|
206
|
+
file = open(filename)
|
207
|
+
unless file
|
208
|
+
puts "#{Cluster::NAME} cannot open file '#{filename}' for reading."
|
209
|
+
exit 2
|
210
|
+
end
|
211
|
+
|
212
|
+
key ||= File.basename(filename)
|
213
|
+
begin
|
214
|
+
@sub.save_monitor file, key
|
215
|
+
rescue => err
|
216
|
+
puts "#{Cluster::NAME} could not save monitor configuration: #{err.message}\n\t#{err.backtrace.join("\n\t")}"
|
217
|
+
exit 2
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def credentials_url
|
222
|
+
@sub.credentials_url
|
223
|
+
end
|
224
|
+
|
225
|
+
def fetch_credentials(url)
|
226
|
+
unless Cluster::Configuration.credentials?
|
227
|
+
puts "Need to know where to save the incoming credentials."
|
228
|
+
exit 2
|
229
|
+
end
|
230
|
+
|
231
|
+
out = File.open(Cluster::Configuration[:credentials_file], 'w')
|
232
|
+
open(url).each do |l| out.write(l); end
|
233
|
+
out.close
|
234
|
+
end
|
235
|
+
|
236
|
+
def fetch_monitor(output)
|
237
|
+
monitor = @sub.fetch_monitor
|
238
|
+
unless monitor
|
239
|
+
puts "#{Cluster::NAME} cannot find any monitor information."
|
240
|
+
exit 1
|
241
|
+
end
|
242
|
+
|
243
|
+
File.open(output, 'w') {|f|
|
244
|
+
f.write(monitor)
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
def gemurl
|
249
|
+
Cluster::LOCATION
|
250
|
+
end
|
251
|
+
|
252
|
+
def imageurl
|
253
|
+
Cluster::IMAGES
|
254
|
+
end
|
255
|
+
|
256
|
+
class << self
|
257
|
+
def set_credentials_file
|
258
|
+
unless Cluster::Configuration.credentials?
|
259
|
+
if ENV['CREDENTIALS'] and File.exist?(ENV['CREDENTIALS'])
|
260
|
+
Cluster::Configuration[:credentials_file] = ENV['CREDENTIALS']
|
261
|
+
elsif ENV['HOME'] and File.exist?(File.join(ENV['HOME'], '.cluster', 'credentials.yml'))
|
262
|
+
Cluster::Configuration[:credentials_file] = File.join(ENV['HOME'], '.cluster', 'credentials.yml')
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|