stackster 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in stackster.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/stackster ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'stackster'
4
+ require 'stackster/cli'
5
+
6
+ Stackster::CLI.start
@@ -0,0 +1,46 @@
1
+ require 'fog'
2
+
3
+ module Stackster
4
+ class AWS
5
+ class CloudFormation
6
+
7
+ def initialize(environment)
8
+ c = Config.environment environment
9
+ @connect = Fog::AWS::CloudFormation.new :aws_access_key_id => c['access_key'],
10
+ :aws_secret_access_key => c['secret_key'],
11
+ :region => c['region']
12
+ end
13
+
14
+ def create(args)
15
+ data = { 'Capabilities' => ['CAPABILITY_IAM'],
16
+ 'TemplateBody' => args[:template] }.merge( { 'Parameters' => args[:parameters] } )
17
+ @connect.create_stack(args[:name], data)
18
+ end
19
+
20
+ def destroy(name)
21
+ @connect.delete_stack name
22
+ end
23
+
24
+ def describe_stack(name)
25
+ @connect.describe_stacks('StackName' => name).body['Stacks']
26
+ end
27
+
28
+ def stack_resources(name)
29
+ @connect.describe_stack_resources('StackName' => name).body['StackResources']
30
+ end
31
+
32
+ def stack_events(name)
33
+ @connect.describe_stack_events(name).body['StackEvents']
34
+ end
35
+
36
+ def stack_status(name)
37
+ describe_stack(name).first['StackStatus']
38
+ end
39
+
40
+ def stack_outputs(name)
41
+ describe_stack(name).last['Outputs']
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ require 'fog'
2
+
3
+ module Stackster
4
+ class AWS
5
+ class EC2
6
+
7
+ def initialize(environment)
8
+ c = Config.environment environment
9
+ @connect = Fog::Compute::AWS.new :aws_access_key_id => c['access_key'],
10
+ :aws_secret_access_key => c['secret_key'],
11
+ :region => c['region']
12
+ end
13
+
14
+ def describe_instances
15
+ i = []
16
+ @connect.describe_instances.body['reservationSet'].each do |instance|
17
+ i << instance
18
+ end
19
+ i
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ require 'fog'
2
+
3
+ module Stackster
4
+ class AWS
5
+ class SimpleDB
6
+
7
+ def initialize(environment)
8
+ c = Config.environment environment
9
+ @connect = Fog::AWS::SimpleDB.new :aws_access_key_id => c['access_key'],
10
+ :aws_secret_access_key => c['secret_key'],
11
+ :region => c['region']
12
+ end
13
+
14
+ def domains
15
+ @connect.list_domains.body['Domains']
16
+ end
17
+
18
+ def create_domain(domain)
19
+ @connect.create_domain(domain) unless domains.include? domain
20
+ end
21
+
22
+ def put_attributes(domain, key, attributes, options)
23
+ @connect.put_attributes domain, key, attributes, options
24
+ end
25
+
26
+ def select(query)
27
+ @connect.select(query).body['Items']
28
+ end
29
+
30
+ def delete(domain, key)
31
+ @connect.delete_attributes domain, key
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ require "stackster/aws/cloud_formation"
2
+ require "stackster/aws/ec2"
3
+ require "stackster/aws/simpledb"
@@ -0,0 +1,62 @@
1
+ require 'trollop'
2
+
3
+ module Stackster
4
+ module CLI
5
+ def self.start
6
+ @opts = Trollop::options do
7
+ banner <<-EOS
8
+ build and manage stacks
9
+ EOS
10
+ opt :help, "Display Help"
11
+ opt :attributes, "CSV list of = seperated attributes to set", :type => :string
12
+ opt :environment, "Set the target environment", :type => :string
13
+ opt :name, "Stack name to manage", :type => :string
14
+ opt :template, "Path to the template file", :type => :string
15
+ end
16
+
17
+ @cmd = ARGV.shift
18
+
19
+ unless Config.environments.include? @opts[:environment]
20
+ puts "Please specify a valid environment: #{Config.environments.to_s}"
21
+ exit 1
22
+ end
23
+
24
+ s = Stack.new :environment => @opts[:environment],
25
+ :name => @opts[:name]
26
+ read_attributes
27
+
28
+ case @cmd
29
+ when 'create'
30
+ s.create :attributes => attributes,
31
+ :template => @opts[:template]
32
+ puts "#{@opts[:name]} created."
33
+ when 'destroy', 'delete'
34
+ s.destroy
35
+ puts "#{@opts[:name]} destroyed."
36
+ when 'show'
37
+ sf = StackFormater.new :environment => @opts[:environment],
38
+ :name => @opts[:name]
39
+ puts sf.display_short.to_yaml
40
+ when 'list'
41
+ s = StackLister.new @opts[:environment]
42
+ puts s.all
43
+ else
44
+ puts "Unkown command '#{@cmd}'"
45
+ end
46
+ end
47
+
48
+ def self.attributes
49
+ attrs = []
50
+ read_attributes.each do |attribs|
51
+ a = attribs.split('=')
52
+ attrs << { a.first => a.last }
53
+ end
54
+ attrs
55
+ end
56
+
57
+ def self.read_attributes
58
+ @opts[:attributes].nil? ? [] : @opts[:attributes].split(',')
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,20 @@
1
+ module Stackster
2
+ class Config
3
+ def self.load_config_file(config_file = "#{ENV['HOME']}/.stackster.yml")
4
+ YAML::load File.open( config_file )
5
+ end
6
+
7
+ def self.environment(environment)
8
+ load_config_file[environment]
9
+ end
10
+
11
+ def self.region(environment)
12
+ load_config_file[environment]['region']
13
+ end
14
+
15
+ def self.environments
16
+ load_config_file.keys
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ module Stackster
2
+ class EntryLister
3
+
4
+ def initialize(environment)
5
+ @environment = environment
6
+ @domain = 'stacks'
7
+ @sdb_connect = AWS::SimpleDB.new @environment
8
+ end
9
+
10
+ def all
11
+ @sdb_connect.select "select * from #{@domain}"
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,57 @@
1
+ require 'stackster/entry/entry_lister'
2
+
3
+ module Stackster
4
+ class Entry
5
+ attr_accessor :name, :attributes
6
+
7
+ def initialize(args)
8
+ @environment = args[:environment]
9
+ @domain = 'stacks'
10
+ @sdb_connect = AWS::SimpleDB.new @environment
11
+ self.name = "#{args[:name]}-#{Config.region @environment}"
12
+ create_domain
13
+ get_attributes
14
+ end
15
+
16
+ def self.find(args)
17
+ e = Entry.new :name => args[:name],
18
+ :environment => args[:environment]
19
+ e.get_attributes
20
+ e
21
+ end
22
+
23
+ def create_domain
24
+ @sdb_connect.create_domain(@domain)
25
+ end
26
+
27
+ def get_attributes
28
+ u = {}
29
+ attrs = @sdb_connect.select("select * from stacks where itemName() = '#{name}'")
30
+ if attrs[name]
31
+ attrs[name].each_pair do |k, v|
32
+ u[k] = v.first
33
+ end
34
+ end
35
+ self.attributes = u
36
+ end
37
+
38
+ def save
39
+ attributes.each_pair do |k,v|
40
+ @sdb_connect.put_attributes('stacks', name, { k => v }, { :replace => k })
41
+ end
42
+ end
43
+
44
+ def set_attributes(a)
45
+ a.each { |attribute| set_attribute(attribute) }
46
+ end
47
+
48
+ def set_attribute(attribute)
49
+ self.attributes = attributes.merge(attribute)
50
+ end
51
+
52
+ def delete_attributes
53
+ @sdb_connect.delete('stacks', name)
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,27 @@
1
+ module Stackster
2
+ class InstanceReader
3
+
4
+ def initialize(environment)
5
+ @environment = environment
6
+ @ec2 = AWS::EC2.new @environment
7
+ end
8
+
9
+ # Data structure is return deffernelty for class
10
+ # Currently only supports VPC
11
+ def list_stack_instances(stack_name)
12
+ h = []
13
+ describe_instances.each do |instance|
14
+ tag_set = instance['instancesSet'].first['tagSet']
15
+ if tag_set['aws:cloudformation:stack-name']
16
+ h << instance if tag_set['aws:cloudformation:stack-name'] == stack_name
17
+ end
18
+ end
19
+ h
20
+ end
21
+
22
+ def describe_instances
23
+ @ec2.describe_instances
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1 @@
1
+ require 'stackster/instance/instance_reader'
@@ -0,0 +1,38 @@
1
+ require 'json'
2
+
3
+ module Stackster
4
+ class StackCreater
5
+
6
+ def initialize(args)
7
+ @cf = AWS::CloudFormation.new args[:environment]
8
+ @entry = args[:entry]
9
+ @name = args[:name]
10
+ @template = read_template_from_file args[:template]
11
+ end
12
+
13
+ def read_template_from_file(template_file)
14
+ file = File.open template_file
15
+ file.read
16
+ end
17
+
18
+ def read_parameters_from_template
19
+ t = JSON.parse(@template)
20
+ t['Paramaters'].nil? ? t['Parameters'].keys : []
21
+ end
22
+
23
+ def read_parameters_from_entry
24
+ h = {}
25
+ read_parameters_from_template.each do |p|
26
+ h[p] = @entry.attributes[p] if @entry.attributes[p]
27
+ end
28
+ h
29
+ end
30
+
31
+ def create
32
+ @cf.create :name => @name,
33
+ :parameters => read_parameters_from_entry,
34
+ :template => @template
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ module Stackster
2
+ class StackDestroyer
3
+
4
+ def initialize(args)
5
+ @cf = AWS::CloudFormation.new args[:environment]
6
+ @name = args[:name]
7
+ end
8
+
9
+ def destroy
10
+ @cf.destroy @name
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,39 @@
1
+ module Stackster
2
+ class StackFormater
3
+
4
+ def initialize(args)
5
+ @sr = StackReader.new :name => args[:name],
6
+ :environment => args[:environment]
7
+ end
8
+
9
+ def display_short
10
+ {
11
+ 'attributes' => @sr.attributes,
12
+ 'status' => @sr.status,
13
+ 'outputs' => @sr.outputs,
14
+ 'last_event' => events_summary.first,
15
+ 'resources' => resources_summary,
16
+ 'instances' => instances_public_ip_addresses
17
+ }
18
+ end
19
+
20
+ def instances_public_ip_addresses
21
+ @sr.instances.map { |i| i['instancesSet'].first['ipAddress'] }
22
+ end
23
+
24
+ def resources_summary
25
+ @sr.resources.map do |i|
26
+ { 'LogicalResourceId' => i['LogicalResourceId'],
27
+ 'PhysicalResourceId' => i['PhysicalResourceId'] }
28
+ end
29
+ end
30
+
31
+ def events_summary
32
+ @sr.events.map do |i|
33
+ { 'ResourceStatus' => i['ResourceStatus'],
34
+ 'LogicalResourceId' => i['LogicalResourceId'] }
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ module Stackster
2
+ class StackLister
3
+
4
+ def initialize(environment)
5
+ @environment = environment
6
+ @cf = AWS::CloudFormation.new @environment
7
+ end
8
+
9
+ def all
10
+ e = EntryLister.new @environment
11
+ e.all.keys
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ module Stackster
2
+ class StackReader
3
+
4
+ def initialize(args)
5
+ @name = args[:name]
6
+ @environment = args[:environment]
7
+ @cf = AWS::CloudFormation.new @environment
8
+ @entry = Entry.find :name => @name,
9
+ :environment => @environment
10
+ end
11
+
12
+ def attributes
13
+ @entry.attributes
14
+ end
15
+
16
+ def outputs
17
+ @cf.stack_outputs @name
18
+ end
19
+
20
+ def status
21
+ @cf.stack_status @name
22
+ end
23
+
24
+ def events
25
+ @cf.stack_events @name
26
+ end
27
+
28
+ def resources
29
+ @cf.stack_resources @name
30
+ end
31
+
32
+ def last_event
33
+ events.first
34
+ end
35
+
36
+ def instances
37
+ ir = InstanceReader.new @environment
38
+ ir.list_stack_instances @name
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ require 'stackster/stack/stack_creater'
2
+ require 'stackster/stack/stack_destroyer'
3
+ require 'stackster/stack/stack_reader'
4
+ require 'stackster/stack/stack_formater'
5
+ require 'stackster/stack/stack_lister'
6
+
7
+ module Stackster
8
+ class Stack
9
+
10
+ def initialize(args)
11
+ @name = args[:name]
12
+ @environment = args[:environment]
13
+ @entry = Entry.new :name => @name,
14
+ :environment => @environment
15
+ end
16
+
17
+ def create(args)
18
+ @entry.set_attributes args[:attributes]
19
+ @entry.save
20
+
21
+ s = StackCreater.new :name => @name,
22
+ :environment => @environment,
23
+ :entry => @entry,
24
+ :template => args[:template]
25
+ s.create
26
+ end
27
+
28
+ def destroy
29
+ s = StackDestroyer.new :name => @name,
30
+ :environment => @environment
31
+ s.destroy
32
+ @entry.delete_attributes
33
+ end
34
+
35
+ def show
36
+ s = StackReader.new :name => @name,
37
+ :environment => @environment
38
+ s.show
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module Stackster
2
+ VERSION = "0.0.1"
3
+ end
data/lib/stackster.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "stackster/aws"
2
+ require "stackster/entry"
3
+ require "stackster/stack"
4
+ require "stackster/instance"
5
+ require "stackster/config"
6
+ require "stackster/version"
data/stackster.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "stackster/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "stackster"
7
+ s.version = Stackster::VERSION
8
+ s.authors = ["Brett Weaver"]
9
+ s.email = ["brett@weav.net"]
10
+ s.homepage = ""
11
+ s.summary = %q{I make deployments easier}
12
+ s.description = %q{Thats what I do}
13
+
14
+ s.rubyforge_project = "stackster"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ s.add_runtime_dependency "fog"
24
+ s.add_runtime_dependency "trollop"
25
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stackster
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Brett Weaver
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fog
16
+ requirement: &70312936224120 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70312936224120
25
+ - !ruby/object:Gem::Dependency
26
+ name: trollop
27
+ requirement: &70312936223700 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70312936223700
36
+ description: Thats what I do
37
+ email:
38
+ - brett@weav.net
39
+ executables:
40
+ - stackster
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - Rakefile
47
+ - bin/stackster
48
+ - lib/stackster.rb
49
+ - lib/stackster/aws.rb
50
+ - lib/stackster/aws/cloud_formation.rb
51
+ - lib/stackster/aws/ec2.rb
52
+ - lib/stackster/aws/simpledb.rb
53
+ - lib/stackster/cli.rb
54
+ - lib/stackster/config.rb
55
+ - lib/stackster/entry.rb
56
+ - lib/stackster/entry/entry_lister.rb
57
+ - lib/stackster/instance.rb
58
+ - lib/stackster/instance/instance_reader.rb
59
+ - lib/stackster/stack.rb
60
+ - lib/stackster/stack/stack_creater.rb
61
+ - lib/stackster/stack/stack_destroyer.rb
62
+ - lib/stackster/stack/stack_formater.rb
63
+ - lib/stackster/stack/stack_lister.rb
64
+ - lib/stackster/stack/stack_reader.rb
65
+ - lib/stackster/version.rb
66
+ - stackster.gemspec
67
+ homepage: ''
68
+ licenses: []
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ segments:
80
+ - 0
81
+ hash: -4027145731470457093
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ segments:
89
+ - 0
90
+ hash: -4027145731470457093
91
+ requirements: []
92
+ rubyforge_project: stackster
93
+ rubygems_version: 1.8.16
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: I make deployments easier
97
+ test_files: []