stackster 0.0.1

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/.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: []