mystro-common 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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mystro-common.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Shawn Catanzarite
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Mystro::Common
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'mystro-common'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install mystro-common
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ def changelog(last=nil, single=false)
4
+ command="git --no-pager log --format='%an::::%h::::%s'"
5
+
6
+ list = `git tag`
7
+
8
+ puts "# Changelog"
9
+ puts
10
+
11
+ ordered = list.lines.sort_by {|e| (a,b,c) = e.gsub(/^v/,"").split("."); "%3d%3d%3d" % [a, b, c]}
12
+
13
+ ordered.reject{|e| (a,b,c,d) = e.split("."); !d.nil?}.reverse_each do |t|
14
+ tag = t.chomp
15
+
16
+ if last
17
+ check = { }
18
+ out = []
19
+ log = `#{command} #{last}...#{tag}`
20
+ log.lines.each do |line|
21
+ (who, hash, msg) = line.split('::::')
22
+ unless check[msg]
23
+ unless msg =~ /^Merge branch/ || msg =~ /CHANGELOG/ || msg =~ /^(v|version|changes for|preparing|ready for release|ready to release|bump version)*\s*(v|version)*\d+\.\d+\.\d+/
24
+ msg.gsub(" *", "\n*").gsub(/^\*\*/, " *").lines.each do |l|
25
+ line = l =~ /^(\s+)*\*/ ? l : "* #{l}"
26
+ out << line
27
+ end
28
+ check[msg] = hash
29
+ end
30
+ end
31
+ end
32
+ puts "## #{last}:"
33
+ out.each { |e| puts e }
34
+ #puts log
35
+ puts
36
+ end
37
+
38
+ last = tag
39
+ exit if single
40
+ end
41
+ end
42
+
43
+ desc "generate changelog output"
44
+ task :changelog do
45
+ changelog
46
+ end
47
+
48
+ desc "show current changes (changelog output from HEAD to most recent tag)"
49
+ task :current do
50
+ changelog("HEAD",true)
51
+ end
@@ -0,0 +1,97 @@
1
+ module Mystro
2
+ class Account
3
+ class << self
4
+ #attr_reader :name
5
+ attr_reader :list
6
+ attr_reader :selected
7
+
8
+ def read
9
+ dir = Mystro.directory
10
+ @list = { }
11
+
12
+ Dir["#{dir}/accounts/*.y*ml"].each do |file|
13
+ name = file.gsub(/#{dir}\/accounts\//, "").gsub(/\.(\w+?)$/, "")
14
+ Mystro::Log.debug "loading account '#{name}' '#{file}'"
15
+ @list[name] = self.new(name, file)
16
+ end
17
+
18
+ @selected = default
19
+ end
20
+
21
+ def default
22
+ return ENV['MYSTRO_ACCOUNT'] if ENV['MYSTRO_ACCOUNT']
23
+ return Mystro.config.default_account if Mystro.config.default_account?
24
+ return "default" if list.keys.include?("default")
25
+ list.keys.first
26
+ end
27
+
28
+ def select(name)
29
+ @selected = name
30
+ end
31
+
32
+ #def data(name = get)
33
+ # if @name != name
34
+ # @data = nil
35
+ # @loaded = false
36
+ # @name = nil
37
+ # end
38
+ #
39
+ # @data ||= begin
40
+ # Mystro::Log.debug "loading account"
41
+ # a = Mystro::Model::Account.load(name)
42
+ # a[:name] = name
43
+ #
44
+ # Mystro::Log.debug "loading plugins from account"
45
+ # Mystro::Plugin.load(a[:plugins]) if a[:plugins]
46
+ #
47
+ # a
48
+ # end
49
+ # @name = @data[:name]
50
+ # @loaded = true
51
+ # @data
52
+ #end
53
+ #
54
+ #def get
55
+ # return ENV['RIG_ACCOUNT'] if ENV['RIG_ACCOUNT']
56
+ # return Mystro.config[:account] if Mystro.config[:account]
57
+ # return Mystro.config[:default_account] if Mystro.config[:default_account]
58
+ # return Mystro.config[:accounts].first if Mystro.config[:accounts] && Mystro.config[:accounts].count > 0
59
+ # "default"
60
+ #end
61
+ #
62
+ #def save
63
+ # name = Mystro.account[:name]
64
+ # Mystro::Model::Account.save(name, Mystro.account)
65
+ #end
66
+ end
67
+
68
+ attr_reader :data
69
+ attr_reader :file
70
+ attr_reader :name
71
+
72
+ def initialize(name, file)
73
+ cfg = Mystro.config.to_hash
74
+ account = File.exists?(file) ? YAML.load_file(file) : { }
75
+ @name = name
76
+ @file = file
77
+ @data = Hashie::Mash.new(cfg.deep_merge(account))
78
+ @data.name = name
79
+ end
80
+
81
+ def compute
82
+ @compute ||= Mystro::Connect::Compute.new(self) if @data.compute
83
+ end
84
+
85
+ def balancer
86
+ @balancer ||= Mystro::Connect::Balancer.new(self) if @data.balancer
87
+ end
88
+
89
+ def dns
90
+ @dns ||= Mystro::Connect::Dns.new(self) if @data.dns
91
+ end
92
+
93
+ def environment
94
+ @environment ||= Mystro::Connect::Environment.new(self)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,50 @@
1
+ ## integration with capistrano
2
+ ## have some helpers to use mystro to get the
3
+ ## host lists for capistrano to use.
4
+ #
5
+ #require 'mystro'
6
+ #require 'mystro/model'
7
+ #require 'capistrano'
8
+ #
9
+ #module Mystro
10
+ # module Capistrano
11
+ # def servers
12
+ # env = Mystro.config[:environment]
13
+ # role = Mystro.config[:role]
14
+ # servers = Mystro::Model::Environment.find(env).servers
15
+ # list = role == 'all' ? servers : servers.select { |s| (s.tags['Roles']||"").split(",").include?(role) }
16
+ #
17
+ # raise "Mystro could not find any servers matching environment=#{env} and role=#{role}" unless list && list.count > 0
18
+ # list.each do |s|
19
+ # server "#{s.tags['Name']}.#{Mystro.get_config(:dns_zone)}", :web, :app
20
+ # end
21
+ # rescue => e
22
+ # puts "*** servers not found: #{e.message}"
23
+ # end
24
+ # end
25
+ #end
26
+ #
27
+ #::Capistrano.plugin :mystro, Mystro::Capistrano
28
+ #
29
+ #configuration = Capistrano::Configuration.respond_to?(:instance) ?
30
+ # Capistrano::Configuration.instance(:must_exist) :
31
+ # Capistrano.configuration(:must_exist)
32
+ #
33
+ #configuration.load do
34
+ # puts " * reading mystro information..."
35
+ #
36
+ # Mystro.config[:environment] = ENV['ENVIRONMENT'] || ARGV[0]
37
+ # Mystro.config[:role] = ENV['ROLE'] || ARGV[1]
38
+ #
39
+ # # create dummy tasks for environment and role
40
+ # begin
41
+ # ARGV.first(2).each do |arg|
42
+ # task arg do
43
+ # nil
44
+ # end
45
+ # end
46
+ # rescue
47
+ # nil
48
+ # end
49
+ #
50
+ #end
@@ -0,0 +1,11 @@
1
+ module Mystro
2
+ module Common
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 1
6
+ TINY = 0
7
+ TAG = nil
8
+ STRING = [MAJOR, MINOR, TINY, TAG].compact.join(".")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ module Mystro
2
+ class Config
3
+ class << self
4
+ def instance
5
+ @instance ||= self.new
6
+ end
7
+ end
8
+
9
+ attr_reader :data
10
+
11
+ def initialize
12
+ f = "#{Mystro.directory}/config.yml"
13
+ d = File.exists?(f) ? YAML.load_file(f) : {}
14
+ c = Hashie::Mash.new(d)
15
+
16
+ if c.logging?
17
+ c.logging.each do |level, dest|
18
+ Mystro::Log.add(level.to_sym, dest)
19
+ end
20
+ end
21
+
22
+ Mystro::Log.debug "loading plugins from configuration"
23
+ Mystro::Plugin.load(c[:plugins]) if c[:plugins]
24
+ @raw = c
25
+ @data = Hashie::Mash.new(c)
26
+ @data.directory = Mystro.directory
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,91 @@
1
+
2
+ module Mystro
3
+ module Connect
4
+ class Balancer < Base
5
+ self.model = "Fog::Balancer"
6
+ self.collection = :load_balancers
7
+
8
+ def all
9
+ fog.send(collection).all
10
+ end
11
+
12
+ def create(model)
13
+ balancer = fog.send(collection).create(model.fog_options)
14
+ balancer.register_instances(model.computes.collect{|e| e.rid})
15
+ balancer.save
16
+ end
17
+
18
+ def find_by_environment(name)
19
+ all.select {|e| e.id =~ /^#{name}\-/}
20
+ end
21
+
22
+ def listener_find(id, from)
23
+ balancer = find(id)
24
+ (from_proto, from_port) = from.split(':')
25
+ match = balancer.listeners.select {|l| l.protocol == from_proto && l.lb_port == from_port.to_i }
26
+ raise "no listeners #{from} found" if match.count == 0
27
+ raise "more than one listener matched #{from}" if match.count > 1
28
+ match.first
29
+ end
30
+
31
+ def listener_create(id, model)
32
+ Mystro::Log.debug "balancer#add_listener #{id} #{model.inspect}"
33
+ lb = find(id)
34
+ opts = model.fog_options
35
+ ap opts
36
+ lb.listeners.create(opts)
37
+ end
38
+
39
+ def listener_destroy(id, from)
40
+ Mystro::Log.debug "balancer#rm_listener #{id} #{from}"
41
+ listener = listener_find(id, from)
42
+ listener.destroy
43
+ end
44
+
45
+ def health_check(id, health)
46
+ Mystro::Log.debug "balancer#health_check #{id} #{health.inspect}"
47
+ balancer = find(id)
48
+ raise "balancer #{id} not found" unless balancer
49
+
50
+ fog.configure_health_check(id, health.fog_options)
51
+ end
52
+
53
+ def sticky(id, type, expires_or_cookie, port, policy=nil)
54
+ balancer = find(id)
55
+ raise "balancer #{id} not found" unless balancer
56
+
57
+ policy ||= "sticky-#{id}-#{type}-#{port}"
58
+ policies = balancer.attributes["ListenerDescriptions"] ? balancer.attributes["ListenerDescriptions"].inject([]) {|a, e| a << e["PolicyNames"]}.flatten : []
59
+ policies << policy
60
+
61
+ case type.downcase.to_sym
62
+ when :app, :application
63
+ fog.create_app_cookie_stickiness_policy(id, policy, expires_or_cookie)
64
+ fog.set_load_balancer_policies_of_listener(id, port.to_i, policies)
65
+ when :lb, :loadbalancer, :load_balancer
66
+ fog.create_lb_cookie_stickiness_policy(id, policy, expires_or_cookie.to_i)
67
+ fog.set_load_balancer_policies_of_listener(id, port.to_i, policies)
68
+ else
69
+ raise "unknown sticky type #{type}"
70
+ end
71
+ end
72
+
73
+ def unsticky(id, type, port, policy=nil)
74
+ balancer = find(id)
75
+ raise "balancer #{id} not found" unless balancer
76
+
77
+ policy ||= "sticky-#{id}-#{type}-#{port}"
78
+ policies = balancer.attributes["ListenerDescriptions"] ? balancer.attributes["ListenerDescriptions"].inject([]) {|a, e| a << e["PolicyNames"]}.flatten : []
79
+ policies.delete(policy)
80
+
81
+ case type.downcase.to_sym
82
+ when :app, :application, :lb, :loadbalancer, :load_balancer
83
+ fog.set_load_balancer_policies_of_listener(id, port.to_i, policies)
84
+ fog.delete_load_balancer_policy(id, policy)
85
+ else
86
+ raise "unknown sticky type #{type}"
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,100 @@
1
+ module Mystro
2
+ module Connect
3
+ class Compute < Base
4
+ self.model = "Fog::Compute"
5
+ self.collection = :servers
6
+
7
+ def all(filters={ })
8
+ fog.send(collection).all(filters)
9
+ end
10
+
11
+ def running
12
+ all({ "instance-state-name" => "running" })
13
+ end
14
+
15
+ def find(id_or_name)
16
+ if id_or_name =~ /^i-/
17
+ super(id_or_name)
18
+ else
19
+ find_by_name(id_or_name)
20
+ end
21
+ end
22
+
23
+ def find_by_name(name)
24
+ list = find_by_tags(name: name)
25
+ return list if list.count > 0
26
+ find_by_nick(name)
27
+ end
28
+
29
+ def find_by_nick(nick)
30
+ Mystro::Log.debug "compute#find_by_nick #{nick}"
31
+ (name, env) = nick.match(/(\w+)\.(\w+)/)[1..2]
32
+ find_by_environment(env).select { |s| s.tags['Name'] =~ /^#{name}/ }
33
+ rescue => e
34
+ Mystro::Log.error "error finding server by nickname #{nick}. name should be of the form: role#.environment"
35
+ []
36
+ end
37
+
38
+ def find_by_environment(environment)
39
+ find_by_tags(environment: environment)
40
+ end
41
+
42
+ def find_by_environment_and_role(environment, role)
43
+ list = find_by_tags(environment: environment)
44
+ list.select { |s| r = s.tags['Roles'] || s.tags['Role']; r.split(",").include?(role) }
45
+ end
46
+
47
+ def find_by_tags(tags)
48
+ Mystro::Log.debug "compute#find_by_tags #{tags.inspect}"
49
+ filters = tags.inject({ }) { |h, e| (k, v) = e; h["tag:#{k.to_s.capitalize}"] = v; h }
50
+ all(filters)
51
+ end
52
+
53
+ def create(model)
54
+ Mystro::Log.debug "#{cname}#create #{model.inspect}"
55
+ e = fog.send(collection).create(model.fog_options)
56
+ fog.create_tags(e.id, model.fog_tags)
57
+ Mystro::Plugin.run "compute:create", e, model
58
+ e
59
+ end
60
+
61
+ #after :create do |compute, model|
62
+ # Mystro::Log.debug "compute#after_create #{compute.id} #{model.fog_tags}"
63
+ # Mystro::Log.debug "#{cname}#create #{fog.inspect}"
64
+ # sleep 3
65
+ #end
66
+
67
+ def destroy(models)
68
+ list = [*models].flatten
69
+ list.each do |m|
70
+ Mystro::Log.debug "#{cname}#destroy #{m.rid}"
71
+ e = find(m.rid)
72
+ Mystro::Plugin.run "compute:destroy", e, m
73
+ e.destroy
74
+ tags = e.tags.keys.inject({ }) { |h, e| h[e] = nil; h }
75
+ fog.create_tags([e.id], tags)
76
+ end
77
+ end
78
+
79
+ #def destroy(list)
80
+ # list = [*list]
81
+ # if list.count > 0
82
+ # ids = list.map {|e| e.kind_of?(String) ? e : e.id}
83
+ # Mystro::Log.debug "compute#destroy: #{ids.inspect}"
84
+ # list.each do |e|
85
+ # Mystro::Plugin.run "compute:destroy", e
86
+ # e.destroy
87
+ # tags = e.tags.keys.inject({}) {|h, e| h[e] = nil; h }
88
+ # fog.create_tags(ids, tags)
89
+ # end
90
+ # end
91
+ #end
92
+
93
+ #after :destroy do |compute, tags|
94
+ # Mystro::Log.debug "#{cname}#after_destroy"
95
+ # tags = compute.tags.keys.inject({ }) { |h, e| h[e] = nil; h }
96
+ # fog.create_tags([compute.id], tags) if tags.count > 0
97
+ #end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,38 @@
1
+
2
+ module Mystro
3
+ module Connect
4
+ class Dns < Base
5
+ self.model = "Fog::DNS"
6
+ self.collection = :records
7
+
8
+ def find_by_endpoint(dns)
9
+ all.select {|e| [*e.value].flatten.include?(dns)}
10
+ end
11
+
12
+ # customize the connect function, because we are defaulting
13
+ # to the zone from the configuration
14
+ def connect
15
+ @fog ||= begin
16
+ raise "could not connect to DNS; #{opt.to_hash.inspect}; #{cfg.to_hash.inspect}" unless opt && cfg.zone
17
+ dns = Fog::DNS.new(opt)
18
+ dns.zones.find(cfg.zone).first
19
+ end
20
+ rescue => e
21
+ Mystro::Log.error "DNS connect failed: #{e.message} at #{e.backtrace.first}"
22
+ Mystro::Log.error e
23
+ end
24
+
25
+ def zones
26
+ Fog::DNS.new(opt).zones.all
27
+ end
28
+
29
+ def zone(name)
30
+ Fog::DNS.new(opt).zones.find(name).first
31
+ end
32
+
33
+ def create_zone(model)
34
+ Fog::DNS.new(opt).zones.create(model.fog_options)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ module Mystro
2
+ module Connect
3
+ class Environment < Base
4
+ def connect
5
+
6
+ end
7
+
8
+ def connected?
9
+ true
10
+ end
11
+
12
+ def find(name)
13
+ Mystro::Model::Environment.load(name)
14
+ end
15
+
16
+ def all
17
+ list = Mystro.compute.all
18
+ list.inject([]) { |a, e| a << e.tags["Environment"] }.compact.uniq.sort
19
+ end
20
+
21
+ def create(model)
22
+ Mystro::Log.info "model: #{model}"
23
+ list = model.template_to_models
24
+ end
25
+
26
+ def destroy
27
+
28
+ end
29
+ end
30
+ end
31
+ end