hugo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ module Hugo; end
2
+
3
+ class Hugo::Database
4
+ include Singleton
5
+ include Hugo::Mixin::ParamsValidate
6
+
7
+ DEFAULT_SERVER = "DEFAULT"
8
+ DEFAULT_SIZE = 5
9
+ DEFAULT_ZONE = 'us-east-1c'
10
+
11
+
12
+ def initialize
13
+ size DEFAULT_SIZE
14
+ zone DEFAULT_ZONE
15
+ server DEFAULT_SERVER
16
+ db_security_group "default"
17
+ end
18
+
19
+ def deploy
20
+ Hugo::Aws::Rds.find_or_create( :name => name,
21
+ :server => server,
22
+ :user => user,
23
+ :password => password,
24
+ :size => size,
25
+ :zone => zone,
26
+ :db_security_group => db_security_group
27
+ )
28
+ end
29
+
30
+ def name(arg=nil)
31
+ set_or_return(:name, arg, :kind_of => [String])
32
+ end
33
+
34
+ def server(arg=nil)
35
+ set_or_return(:server, arg, :kind_of => [String])
36
+ end
37
+
38
+ def user(arg=nil)
39
+ set_or_return(:user, arg, :kind_of => [String])
40
+ end
41
+
42
+ def password(arg=nil)
43
+ set_or_return(:password, arg, :kind_of => [String])
44
+ end
45
+
46
+ def size(arg=nil)
47
+ set_or_return(:size, arg, :kind_of => [Integer])
48
+ end
49
+
50
+ def zone(arg=nil)
51
+ set_or_return(:zone, arg, :kind_of => [String])
52
+ end
53
+
54
+ def db_security_group(arg=nil)
55
+ set_or_return(:db_security_group, arg, :kind_of => [String])
56
+ end
57
+
58
+ end
@@ -0,0 +1,197 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
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
+ module Hugo
19
+ module Mixin
20
+ module ParamsValidate
21
+
22
+ # Takes a hash of options, along with a map to validate them. Returns the original
23
+ # options hash, plus any changes that might have been made (through things like setting
24
+ # default values in the validation map)
25
+ #
26
+ # For example:
27
+ #
28
+ # validate({ :one => "neat" }, { :one => { :kind_of => String }})
29
+ #
30
+ # Would raise an exception if the value of :one above is not a kind_of? string. Valid
31
+ # map options are:
32
+ #
33
+ # :default:: Sets the default value for this parameter.
34
+ # :callbacks:: Takes a hash of Procs, which should return true if the argument is valid.
35
+ # The key will be inserted into the error message if the Proc does not return true:
36
+ # "Option #{key}'s value #{value} #{message}!"
37
+ # :kind_of:: Ensure that the value is a kind_of?(Whatever). If passed an array, it will ensure
38
+ # that the value is one of those types.
39
+ # :respond_to:: Ensure that the value has a given method. Takes one method name or an array of
40
+ # method names.
41
+ # :required:: Raise an exception if this parameter is missing. Valid values are true or false,
42
+ # by default, options are not required.
43
+ # :regex:: Match the value of the paramater against a regular expression.
44
+ # :equal_to:: Match the value of the paramater with ==. An array means it can be equal to any
45
+ # of the values.
46
+ def validate(opts, map)
47
+ #--
48
+ # validate works by taking the keys in the validation map, assuming it's a hash, and
49
+ # looking for _pv_:symbol as methods. Assuming it find them, it calls the right
50
+ # one.
51
+ #++
52
+ raise ArgumentError, "Options must be a hash" unless opts.kind_of?(Hash)
53
+ raise ArgumentError, "Validation Map must be a hash" unless map.kind_of?(Hash)
54
+
55
+ map.each do |key, validation|
56
+ unless key.kind_of?(Symbol) || key.kind_of?(String)
57
+ raise ArgumentError, "Validation map keys must be symbols or strings!"
58
+ end
59
+ case validation
60
+ when true
61
+ _pv_required(opts, key)
62
+ when false
63
+ true
64
+ when Hash
65
+ validation.each do |check, carg|
66
+ check_method = "_pv_#{check.to_s}"
67
+ if self.respond_to?(check_method, true)
68
+ self.send(check_method, opts, key, carg)
69
+ else
70
+ raise ArgumentError, "Validation map has unknown check: #{check}"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ opts
76
+ end
77
+
78
+ def set_or_return(symbol, arg, validation)
79
+ iv_symbol = "@#{symbol.to_s}".to_sym
80
+ map = {
81
+ symbol => validation
82
+ }
83
+ if arg == nil
84
+ self.instance_variable_get(iv_symbol)
85
+ else
86
+ validate({ symbol => arg }, { symbol => validation })
87
+ self.instance_variable_set(iv_symbol, arg)
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ # Return the value of a parameter, or nil if it doesn't exist.
94
+ def _pv_opts_lookup(opts, key)
95
+ if opts.has_key?(key.to_s)
96
+ opts[key.to_s]
97
+ elsif opts.has_key?(key.to_sym)
98
+ opts[key.to_sym]
99
+ else
100
+ nil
101
+ end
102
+ end
103
+
104
+ # Raise an exception if the parameter is not found.
105
+ def _pv_required(opts, key, is_required=true)
106
+ if is_required
107
+ if opts.has_key?(key.to_s) || opts.has_key?(key.to_sym)
108
+ true
109
+ else
110
+ raise ArgumentError, "Required argument #{key} is missing!"
111
+ end
112
+ end
113
+ end
114
+
115
+ def _pv_equal_to(opts, key, to_be)
116
+ value = _pv_opts_lookup(opts, key)
117
+ if value != nil
118
+ passes = false
119
+ [ to_be ].flatten.each do |tb|
120
+ if value == tb
121
+ passes = true
122
+ end
123
+ end
124
+ unless passes
125
+ raise ArgumentError, "Option #{key} must be equal to one of: #{to_be.join(", ")}! You passed #{value.inspect}."
126
+ end
127
+ end
128
+ end
129
+
130
+ # Raise an exception if the parameter is not a kind_of?(to_be)
131
+ def _pv_kind_of(opts, key, to_be)
132
+ value = _pv_opts_lookup(opts, key)
133
+ if value != nil
134
+ passes = false
135
+ [ to_be ].flatten.each do |tb|
136
+ if value.kind_of?(tb)
137
+ passes = true
138
+ end
139
+ end
140
+ unless passes
141
+ raise ArgumentError, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}."
142
+ end
143
+ end
144
+ end
145
+
146
+ # Raise an exception if the parameter does not respond to a given set of methods.
147
+ def _pv_respond_to(opts, key, method_name_list)
148
+ value = _pv_opts_lookup(opts, key)
149
+ if value != nil
150
+ [ method_name_list ].flatten.each do |method_name|
151
+ unless value.respond_to?(method_name)
152
+ raise ArgumentError, "Option #{key} must have a #{method_name} method!"
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ # Assign a default value to a parameter.
159
+ def _pv_default(opts, key, default_value)
160
+ value = _pv_opts_lookup(opts, key)
161
+ if value == nil
162
+ opts[key] = default_value
163
+ end
164
+ end
165
+
166
+ # Check a parameter against a regular expression.
167
+ def _pv_regex(opts, key, regex)
168
+ value = _pv_opts_lookup(opts, key)
169
+ passes = false
170
+ [ regex ].flatten.each do |r|
171
+ if value != nil
172
+ if r.match(value.to_s)
173
+ passes = true
174
+ end
175
+ end
176
+ end
177
+ unless passes
178
+ raise ArgumentError, "Option #{key}'s value #{value} does not match regular expression #{regex.to_s}"
179
+ end
180
+ end
181
+
182
+ # Check a parameter against a hash of proc's.
183
+ def _pv_callbacks(opts, key, callbacks)
184
+ raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash)
185
+ value = _pv_opts_lookup(opts, key)
186
+ if value != nil
187
+ callbacks.each do |message, zeproc|
188
+ if zeproc.call(value) != true
189
+ raise ArgumentError, "Option #{key}'s value #{value} #{message}!"
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+
@@ -0,0 +1,83 @@
1
+ # Hugo (Cloud DSL)
2
+ <small>A simple dsl to deploy to the cloud</small>
3
+
4
+ Currently only supports Amazon Web Services, but will be expanded soon!
5
+
6
+ ## Requirements
7
+
8
+ First, you need a Amazon AWS Account
9
+
10
+ You need to configure you system to contain AWS info in environment variables.
11
+
12
+ Make sure you are enabled to generate ELB, RDS, and EC2.
13
+
14
+ Make sure you have a keypair generated for you AWS Account!
15
+
16
+ ## What does it look like?
17
+
18
+ # mycloud.rb
19
+ require 'lib/hugo'
20
+
21
+ config = YAML.load_file("mycloud.yml")
22
+
23
+ Hugo do
24
+ cloud "mycloud" do
25
+ balancer
26
+
27
+ database "sample_app_production" do
28
+ server "company_server"
29
+ user "admin"
30
+ password "admin"
31
+ end
32
+
33
+ app "sample_app" do
34
+ key_name "my-keypair"
35
+
36
+ cookbook "git://github.com/twilson63/hugo-cookbooks.git"
37
+ key_pair_file "~/.ec2/my-keypair"
38
+ port "8080"
39
+ github_url "git@github.com:twilson63"
40
+ privatekey config["github"]["privatekey"]
41
+ publickey config["github"]["publickey"]
42
+ package_list config["package_list"]
43
+ gem_list config["gem_list"]
44
+ run_list ["role[web-base]", "role[web-app]"]
45
+
46
+ deploy_info :web_server_name => "sample_app.jackhq.com",
47
+ :restart_command => "gem bundle && touch tmp/restart.txt"
48
+
49
+ servers 2
50
+
51
+ end
52
+
53
+ deploy
54
+
55
+ print
56
+ end
57
+
58
+ ---
59
+
60
+ ## What about the config file?
61
+
62
+ # mycloud.yml
63
+
64
+ github:
65
+ url: XXXX
66
+ publickey: XXX
67
+ privatekey: XXX
68
+
69
+ package_list:
70
+ - name: mysql-client
71
+ - name: libmysqlclient15-dev
72
+ - name: libmysql-ruby1.8
73
+ - name: libexpat1
74
+ - name: libxml2
75
+ - name: libxml2-dev
76
+ - name: libxslt1-dev
77
+ - name: sqlite3
78
+ - name: libsqlite3-dev
79
+
80
+ gem_list:
81
+ - name: bundler
82
+
83
+
Binary file
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe "Hugo App" do
4
+ before(:each) do
5
+ mocks
6
+ end
7
+
8
+ it "should be valid" do
9
+
10
+ block = lambda do
11
+ cloud "my_cloud" do
12
+ balancer
13
+ app "testapp" do
14
+ servers 0
15
+ end
16
+ end
17
+ end
18
+
19
+ lambda do
20
+ Hugo &block
21
+ end.should_not raise_error
22
+ end
23
+
24
+ it "should raise error for database block not wrapped in cloud block" do
25
+ block = lambda do
26
+ app "myapp" do end
27
+ end
28
+
29
+ lambda do
30
+ Hugo &block
31
+ end.should raise_error
32
+ end
33
+
34
+ it "should not raise error for database block wrapped in cloud block" do
35
+ block = lambda do
36
+ cloud "mycloud" do
37
+ app "myapp" do end
38
+ end
39
+ end
40
+
41
+ lambda do
42
+ Hugo &block
43
+ end.should be_true
44
+ end
45
+ end
46
+
47
+ # describe Hugo::App do
48
+ # before(:each) do
49
+ # mocks
50
+ # end
51
+ #
52
+ #
53
+ # it "should create a new ec2 instance" do
54
+ #
55
+ # app = Hugo::App.instance
56
+ # app.key_name "ec2-keypair"
57
+ #
58
+ # app.servers 1
59
+ # app.name "mydb"
60
+ # #app.deploy.should be_a_kind_of(Hugo::Aws::Rds)
61
+ # end
62
+ #
63
+ #
64
+ # end
@@ -0,0 +1,55 @@
1
+ require File.dirname(__FILE__) + '/../../../spec_helper'
2
+
3
+ describe Hugo::Aws::Ec2 do
4
+ before(:each) do
5
+ @mock = mock('AWS::EC2::Base')
6
+ instance = {"requestId"=>"e280b5aa-9b60-458f-b16f-96f97eb5e628", "reservationSet"=>
7
+ {"item"=>[{"reservationId"=>"r-ff5d8797", "groupSet"=>{"item"=>[{"groupId"=>"default"}]},
8
+ "instancesSet"=>{"item"=>[{"privateIpAddress"=>"10.210.43.6", "keyName"=>"ec2-keypair", "ramdiskId"=>"ari-0915f660", "productCodes"=>nil, "ipAddress"=>"174.129.63.98", "kernelId"=>"aki-5f15f636", "launchTime"=>"2009-11-29T13:20:48.000Z", "amiLaunchIndex"=>"0",
9
+ "imageId"=>"ami-1515f67c", "instanceType"=>"m1.small", "reason"=>nil, "placement"=>{"availabilityZone"=>"us-east-1c"},
10
+ "instanceId"=>"i-12345678", "privateDnsName"=>"domU-XXXX.compute-1.internal",
11
+ "dnsName"=>"ec2-XXX.compute-1.amazonaws.com", "monitoring"=>{"state"=>"enabled"},
12
+ "instanceState"=>{"name"=>"running", "code"=>"16"}}]}, "ownerId"=>"398217953086"}]}, "xmlns"=>"http://ec2.amazonaws.com/doc/2009-07-15/"}
13
+
14
+ @mock.stub!(:run_instances).and_return(instance)
15
+ @mock.stub!(:describe_instances).and_return(instance)
16
+ @mock.stub!(:terminate_instances).and_return(instance)
17
+
18
+ security_group = {"group_name"=>"test", "group_description"=>"test description"}
19
+ @mock.stub!(:create_security_groups).and_return(security_group)
20
+ @mock.stub!(:describe_security_groups).and_return(security_group)
21
+ @mock.stub!(:delete_security_group).and_return(security_group)
22
+
23
+ AWS::EC2::Base.stub!(:new).and_return(@mock)
24
+ end
25
+
26
+ # it "should create a new instance" do
27
+ # @ec2 = Hugo::Aws::Ec2.new()
28
+ # @ec2.save.should be_true
29
+ # end
30
+
31
+ it "should terminate instance" do
32
+ Hugo::Aws::Ec2.find('i-12345678').destroy.should be_true
33
+ end
34
+
35
+ it "should find instance" do
36
+ Hugo::Aws::Ec2.find('i-12345678').should_not be_nil
37
+ end
38
+
39
+ it "should return all instances" do
40
+ Hugo::Aws::Ec2.all.length.should == 1
41
+ end
42
+
43
+ it "should find or create security group" do
44
+ Hugo::Aws::Ec2.find_or_create_security_group('test', 'test description').should_not be_empty
45
+ end
46
+
47
+ it "should destroy a security group" do
48
+ Hugo::Aws::Ec2.destroy_security_group('test').should be_true
49
+ end
50
+ #
51
+ # it "should deploy app" do
52
+ #
53
+ # end
54
+ #
55
+ end