hugo 0.1.0

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.
@@ -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