simple_stack 0.0.28 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 564184d6c196cb5f443bc0ceda251d9c2b7e68f5
4
- data.tar.gz: ac515a412f16537fb71f22119073c48ad732743d
3
+ metadata.gz: ec7852762d8fb5388f29dbcb6d0c889958c4409e
4
+ data.tar.gz: 9b6c5482c4d1ff94cf126a6656292b8bf92f5f69
5
5
  SHA512:
6
- metadata.gz: 8a0f4da480ab25fd95b088984a31872c61be55a5edfd048c1ed603d5a05a7e5717dd52759f5d53b35567c8b0494c845708975e20ba5bcb12d07ceb4cefc8b40f
7
- data.tar.gz: 4d5bb43f57d3709ca6a559d669a88a9a7610c5cd5467cc089899a3f8c110f616d573a8a807466e1ca139e48399fc1812ff6a8c4e2dec3ba9938aae5578c37e21
6
+ metadata.gz: 4cf1159e2b0ba0c68cd11bd2f587e314959a37e5999b69683af636fb790efe93e76c25e6ca5acafdc2cb694e2bb8073ffaadee48128f5c70cd3db142838f0d15
7
+ data.tar.gz: 0572cb6541a74fa415a9c836b18e54dd5581465fb07ef5e9eedf5b95ed24342b285688046cb5b44d39ab67ac8490c72db775b45e77e8e8fadd870efd148fc508
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in simplestack.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,72 @@
1
+ Simplestack ruby client
2
+ =======================
3
+
4
+ A simple gem to deal with Simple Stack project.
5
+
6
+ Get a simplestack class:
7
+
8
+ stack = SimpleStack::Connection.new :url => url, :username => username, :password => password
9
+
10
+ Connecting to hypervisor:
11
+
12
+ vmware = stack.connect_to("vmware", :host => host, :username => username, :password => password)
13
+
14
+ Pool informations:
15
+
16
+ vmware.info
17
+ vmware.guests
18
+
19
+ # TODO:
20
+ # vmware.used_memory
21
+ # vmware.total_memory
22
+ # vmware.import vm_file
23
+
24
+ Working with Guests
25
+ -------------------
26
+
27
+ guest = vmware.guests.find(vm.uuid)
28
+ guest.info
29
+ guest.update(:name => "Guest name", :memory => 512)
30
+ guest.delete
31
+
32
+ Shutdown and power on and reboot
33
+
34
+ guest.stop
35
+ guest.start
36
+ guest.reboot
37
+
38
+ Force the guest shutdown
39
+
40
+ guest.force_stop
41
+
42
+ Resume and suspend guests
43
+
44
+ guest.resume
45
+ guest.pause
46
+
47
+ TODO:
48
+
49
+ file = guest.export :to => file_path
50
+
51
+ Snapshots
52
+ ---------
53
+
54
+ List snapshots
55
+
56
+ guest.snapshots
57
+
58
+ Find a snapshot
59
+
60
+ guest.snapshots.find(snap.uuid)
61
+
62
+ Create a new snapshot
63
+
64
+ snap = guest.snapshots.create :name => :snapshot_name
65
+
66
+ Delete a snapshot
67
+
68
+ snap.delete
69
+
70
+ Revert a snapshot
71
+
72
+ snap.use
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ module SimpleStack
2
+ module Cacheable
3
+ def reload
4
+ @cached_attributes = {}
5
+ self
6
+ end
7
+
8
+ def cacheable?
9
+ if respond_to? :connection
10
+ connection.cache_enabled
11
+ else
12
+ false
13
+ end
14
+ end
15
+
16
+ def cached_attributes
17
+ if cacheable?
18
+ @cached_attributes ||= {}
19
+ else
20
+ {}
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,45 @@
1
+ module SimpleStack
2
+ class Collection
3
+ include SimpleStack::Cacheable
4
+
5
+ attr_accessor :hypervisor, :parent, :url, :clazz
6
+
7
+ def initialize(hypervisor, parent, url, clazz)
8
+ self.hypervisor = hypervisor
9
+ self.parent = parent
10
+ self.url = url.to_s
11
+ self.clazz = clazz
12
+ end
13
+
14
+ def to_a
15
+ cached_attributes[:items] ||= hypervisor.get(url).map do |item|
16
+ clazz.new hypervisor, self, "#{url}/#{item["id"]}"
17
+ end
18
+ end
19
+
20
+ def find(id)
21
+ clazz.new hypervisor, self, "#{url}/#{id}"
22
+ end
23
+
24
+ def create(options={})
25
+ response = hypervisor.post(url, options)
26
+ entity_path = response.headers["location"].sub(/^\//, "").sub(/\/$/, "")
27
+ entity_url = "#{connection.url}/#{entity_path}"
28
+ new_item = clazz.new hypervisor, self, entity_url
29
+ reload if cacheable?
30
+ new_item
31
+ end
32
+
33
+ def method_missing(method, *args, &block)
34
+ to_a.send(method, *args, &block)
35
+ end
36
+
37
+ def inspect
38
+ to_a.inspect
39
+ end
40
+
41
+ def connection
42
+ hypervisor.connection
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ module SimpleStack
2
+ class Connection
3
+ attr_accessor :url, :graceful_degradation, :cache_enabled, :timeout, :read_timeout
4
+
5
+ def initialize(options = {})
6
+ self.url = options[:url].to_s.sub(/\/$/, "")
7
+ self.graceful_degradation = options[:graceful_degradation]
8
+ self.cache_enabled = options[:cache_enabled]
9
+ self.timeout = options[:timeout] || 60
10
+ self.read_timeout = options[:read_timeout] || timeout
11
+ end
12
+
13
+ def connect_to(type, options)
14
+ SimpleStack::Hypervisor.new self, type, options
15
+ end
16
+
17
+ def token
18
+ "TODO"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module SimpleStack
2
+ class Disk < Entity
3
+ end
4
+ end
@@ -0,0 +1,44 @@
1
+ module SimpleStack
2
+ class Entity
3
+ include SimpleStack::Cacheable
4
+
5
+ attr_accessor :hypervisor, :parent, :url
6
+
7
+ def initialize(hypervisor, parent, url)
8
+ self.hypervisor = hypervisor
9
+ self.parent = parent
10
+ self.url = url.to_s
11
+ end
12
+
13
+ def info
14
+ cached_attributes[:info] ||= hypervisor.get(url).parsed_response
15
+ end
16
+
17
+ def update(attributes = {})
18
+ hypervisor.put url, attributes
19
+ end
20
+
21
+ def delete
22
+ response = hypervisor.delete url
23
+ parent.reload if cacheable?
24
+ response
25
+ end
26
+
27
+ def inspect
28
+ "#<#{self.class} info=#{info.to_json}>"
29
+ end
30
+
31
+ def connection
32
+ hypervisor.connection
33
+ end
34
+
35
+ def method_missing(method, *args, &block)
36
+ entity_info = info
37
+ if entity_info.keys.include?(method.to_s)
38
+ entity_info[method.to_s]
39
+ else
40
+ super
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,87 @@
1
+ module SimpleStack
2
+ class Exception < ::Exception
3
+ def self.factory(error)
4
+ return Exception.new(error.inspect) if !error.is_a?(Hash)
5
+ case error["error"]
6
+ when "EntityNotFound"
7
+ EntityNotFound.new(error["message"])
8
+ when "FeatureNotImplemented"
9
+ NotImplemented.new(error["message"])
10
+ when "FeatureNotAvailable"
11
+ NotImplemented.new(error["message"])
12
+ when "HypervisorError"
13
+ HypervisorError.new(error["message"])
14
+ else
15
+ Exception.new(error.inspect)
16
+ end
17
+ end
18
+ end
19
+
20
+ class EntityNotFound < Exception
21
+ end
22
+
23
+ class HypervisorError < Exception
24
+ end
25
+
26
+ class NotImplemented < Exception
27
+ end
28
+
29
+ class GracefulObject
30
+ def [](key)
31
+ GracefulObject.new
32
+ end
33
+
34
+ def []=(key, value)
35
+ GracefulObject.new
36
+ end
37
+
38
+ def +(other)
39
+ other + self
40
+ end
41
+
42
+ def -(other)
43
+ -(other - self)
44
+ end
45
+
46
+ def *(other)
47
+ other * self
48
+ end
49
+
50
+ def to_i
51
+ 0
52
+ end
53
+
54
+ def to_f
55
+ 0.0
56
+ end
57
+
58
+ def to_str
59
+ "GracefulObject"
60
+ end
61
+ alias :to_s :to_str
62
+
63
+ def to_ary
64
+ []
65
+ end
66
+ alias :to_a :to_ary
67
+
68
+ def to_hash
69
+ {}
70
+ end
71
+
72
+ def coerce(other)
73
+ coerced = if other.is_a? Fixnum
74
+ self.to_i
75
+ elsif other.is_a? String
76
+ self.to_s
77
+ elsif other.is_a? Array
78
+ self.to_a
79
+ elsif other.is_a? Hash
80
+ self.to_hash
81
+ else
82
+ nil
83
+ end
84
+ [coerced, other]
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,86 @@
1
+ module SimpleStack
2
+ class Guest < Entity
3
+ def disks
4
+ cached_attributes[:disks] ||= SimpleStack::Collection.new hypervisor, self, "#{url}/disks", SimpleStack::Disk
5
+ end
6
+
7
+ def network_interfaces
8
+ cached_attributes[:network_interfaces] ||= SimpleStack::Collection.new hypervisor, self, "#{url}/network_interfaces", SimpleStack::NetworkInterface
9
+ end
10
+
11
+ def snapshots
12
+ cached_attributes[:snapshots] ||= SimpleStack::Collection.new hypervisor, self, "#{url}/snapshots", SimpleStack::Snapshot
13
+ end
14
+
15
+ def tags
16
+ cached_attributes[:tags] ||= hypervisor.get("#{url}/tags").parsed_response
17
+ end
18
+
19
+ def add_tag(tag)
20
+ hypervisor.post "#{url}/tags", :name => tag
21
+ reload if cacheable?
22
+ tag
23
+ end
24
+
25
+ def remove_tag(tag)
26
+ hypervisor.delete "#{url}/tags/#{tag}"
27
+ reload if cacheable?
28
+ tag
29
+ end
30
+
31
+ def reboot(opts={:force => false})
32
+ hypervisor.put "#{url}/reboot", :force => opts[:force]
33
+ end
34
+
35
+ def export(opts={})
36
+ opts = {:to => "/tmp/export_file"}.merge(opts)
37
+ file = File.open(opts[:to], "wb")
38
+
39
+ hypervisor.get_stream("#{url}/export", file)
40
+
41
+ opts[:to]
42
+ ensure
43
+ file.close rescue nil
44
+ end
45
+
46
+ def revert_to(snapshot)
47
+ snapshot.revert
48
+ end
49
+
50
+ def clone(opts={})
51
+ response = hypervisor.post("#{url}/clone", opts)
52
+ entity_path = response.headers["location"].sub(/^\//, "").sub(/\/$/, "")
53
+ entity_url = "#{connection.url}/#{entity_path}"
54
+ new_item = SimpleStack::Guest.new hypervisor, self, entity_url
55
+ end
56
+
57
+ def insert_media(media_name, opts={})
58
+ media_options = opts.merge(:name => media_name)
59
+ hypervisor.put("#{url}/media_device", media_options)
60
+ reload if cacheable?
61
+ end
62
+
63
+ def eject_media
64
+ hypervisor.put("#{url}/media_device", :name => nil)
65
+ reload if cacheable?
66
+ end
67
+
68
+ def inserted_media
69
+ if cached_attributes.key? :inserted_media
70
+ cached_attributes[:inserted_media]
71
+ else
72
+ cached_attributes[:inserted_media] = hypervisor.get("#{url}/media_device").parsed_response["name"]
73
+ end
74
+ end
75
+
76
+ def power_state=(state)
77
+ hypervisor.put "#{url}/power", :state => state
78
+ end
79
+
80
+ ["start", "stop", "force_stop", "pause", "resume"].each do |state|
81
+ define_method(state) do
82
+ self.power_state = state
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,4 @@
1
+ module SimpleStack
2
+ class Host < Entity
3
+ end
4
+ end
@@ -0,0 +1,130 @@
1
+ module SimpleStack
2
+ class Hypervisor
3
+ include SimpleStack::Cacheable
4
+
5
+ attr_accessor :connection, :type, :host, :username, :password
6
+
7
+ def initialize(connection, type, options)
8
+ self.connection = connection
9
+ self.type = type
10
+ self.host = options[:host]
11
+ self.username = options[:username]
12
+ self.password = options[:password]
13
+ end
14
+
15
+ def url
16
+ "#{connection.url}/#{type}/#{host}"
17
+ end
18
+
19
+ def headers
20
+ {
21
+ "x-simplestack-version" => "1.0",
22
+ "x-simplestack-token" => connection.token,
23
+ "x-simplestack-hypervisor-token" => token,
24
+ "Content-Type" => "application/json"
25
+ }
26
+ end
27
+
28
+ def http_options
29
+ {
30
+ :timeout => connection.timeout,
31
+ :read_timeout => connection.read_timeout,
32
+ :no_follow => true,
33
+ :headers => headers
34
+ }
35
+ end
36
+
37
+ def token
38
+ Base64.encode64("#{username}:#{password}").split("\n").join("")
39
+ end
40
+
41
+ def info
42
+ cached_attributes[:info] ||= self.get url
43
+ end
44
+
45
+ def hosts
46
+ cached_attributes[:hosts] ||= SimpleStack::Collection.new self, self, "#{url}/hosts", SimpleStack::Host
47
+ end
48
+
49
+ def storages
50
+ cached_attributes[:storages] ||= SimpleStack::Collection.new self, self, "#{url}/storages", SimpleStack::Storage
51
+ end
52
+
53
+ def guests
54
+ cached_attributes[:guests] ||= SimpleStack::Collection.new self, self, "#{url}/guests", SimpleStack::Guest
55
+ end
56
+
57
+ def import(opts={})
58
+ file = File.open(opts[:from], "rb")
59
+
60
+ response = post_stream("#{url}/guests", file)
61
+ entity_path = response["location"].sub(/^\//, "").sub(/\/$/, "")
62
+ entity_url = "#{connection.url}/#{entity_path}"
63
+ SimpleStack::Guest.new self, guests.reload, entity_url
64
+ ensure
65
+ file.close rescue nil
66
+ end
67
+
68
+ def get(url)
69
+ http_call { HTTParty.get(url, http_options) }
70
+ end
71
+
72
+ def get_stream(url, io)
73
+ uri = URI.parse url
74
+ http = Net::HTTP.new(uri.host, uri.port)
75
+ request = Net::HTTP::Get.new(uri.path)
76
+
77
+ headers.each_pair do |k, v|
78
+ request.add_field(k, v)
79
+ end
80
+
81
+ http.request(request) do |res|
82
+ res.read_body {|chunk| io.write chunk }
83
+ end
84
+ end
85
+
86
+ def post(url, body)
87
+ http_call { HTTParty.post(url, http_options.merge(:body => JSON.dump(body))) }
88
+ end
89
+
90
+ def put(url, body)
91
+ http_call { HTTParty.put(url, http_options.merge(:body => JSON.dump(body))) }
92
+ end
93
+
94
+ def post_stream(url, io)
95
+ uri = URI.parse url
96
+ http = Net::HTTP.new(uri.host, uri.port)
97
+ request = Net::HTTP::Post.new(uri.path, {})
98
+
99
+ headers.each_pair do |k, v|
100
+ request.add_field(k, v)
101
+ end
102
+
103
+ request.body_stream = io
104
+ request.content_length = io.size
105
+ response = http.request(request)
106
+
107
+ if response.code.to_i >= 400
108
+ parsed_response = JSON.load(response.body) rescue response.body
109
+ raise SimpleStack::Exception.factory(parsed_response)
110
+ end
111
+
112
+ response
113
+ end
114
+
115
+ def delete(url)
116
+ http_call { HTTParty.delete(url, http_options) }
117
+ end
118
+
119
+ def http_call
120
+ response = yield
121
+ return SimpleStack::GracefulObject.new if response.code == 501 && connection.graceful_degradation
122
+ raise SimpleStack::Exception.factory(response.parsed_response) if response.code >= 400
123
+ response
124
+ end
125
+
126
+ def inspect
127
+ "#<#{self.class} url=#{url}>"
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,4 @@
1
+ module SimpleStack
2
+ class NetworkInterface < Entity
3
+ end
4
+ end
@@ -0,0 +1,11 @@
1
+ module SimpleStack
2
+ class Snapshot < Entity
3
+ def use
4
+ revert
5
+ end
6
+
7
+ def revert
8
+ hypervisor.put "#{url}/revert", {}
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module SimpleStack
2
+ class Storage < Entity
3
+ def import(opts={})
4
+ file = File.open(opts[:from], "rb")
5
+
6
+ response = hypervisor.post_stream("#{url}/guests", file)
7
+ entity_path = response["location"].sub(/^\//, "").sub(/\/$/, "")
8
+ entity_url = "#{connection.url}/#{entity_path}"
9
+ SimpleStack::Guest.new hypervisor, hypervisor.guests.reload, entity_url
10
+ ensure
11
+ file.close rescue nil
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleStack
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,22 @@
1
+ require "json"
2
+ require "base64"
3
+ require "httparty"
4
+ require "simple_stack/version"
5
+ require "simple_stack/exception"
6
+ require "simple_stack/connection"
7
+ require "simple_stack/cacheable"
8
+ require "simple_stack/collection"
9
+ require "simple_stack/hypervisor"
10
+ require "simple_stack/entity"
11
+ require "simple_stack/host"
12
+ require "simple_stack/storage"
13
+ require "simple_stack/guest"
14
+ require "simple_stack/snapshot"
15
+ require "simple_stack/network_interface"
16
+ require "simple_stack/disk"
17
+
18
+ module SimpleStack
19
+ def self.client
20
+ HTTParty
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "simple_stack/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "simple_stack"
7
+ s.version = SimpleStack::VERSION
8
+ s.authors = ["Thiago Morello", "Willian Molinari"]
9
+ s.email = ["thiago.morello@locaweb.com.br", "willian.molinari@locaweb.com.br"]
10
+ s.homepage = "https://github.com/locaweb/ruby-simplestack-client"
11
+ s.summary = %q{A simple gem to work with simplestack project}
12
+ s.description = s.summary
13
+
14
+ s.rubyforge_project = "simple_stack"
15
+
16
+ s.files = Dir["{lib}/**/*"] + ["Rakefile", "README.markdown", "Gemfile", "simple_stack.gemspec"]
17
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rspec"
22
+ s.add_runtime_dependency "httparty"
23
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_stack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.28
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thiago Morello
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-03 00:00:00.000000000 Z
12
+ date: 2013-09-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -46,7 +46,25 @@ email:
46
46
  executables: []
47
47
  extensions: []
48
48
  extra_rdoc_files: []
49
- files: []
49
+ files:
50
+ - lib/simple_stack/snapshot.rb
51
+ - lib/simple_stack/exception.rb
52
+ - lib/simple_stack/network_interface.rb
53
+ - lib/simple_stack/version.rb
54
+ - lib/simple_stack/disk.rb
55
+ - lib/simple_stack/collection.rb
56
+ - lib/simple_stack/connection.rb
57
+ - lib/simple_stack/hypervisor.rb
58
+ - lib/simple_stack/entity.rb
59
+ - lib/simple_stack/storage.rb
60
+ - lib/simple_stack/host.rb
61
+ - lib/simple_stack/cacheable.rb
62
+ - lib/simple_stack/guest.rb
63
+ - lib/simple_stack.rb
64
+ - Rakefile
65
+ - README.markdown
66
+ - Gemfile
67
+ - simple_stack.gemspec
50
68
  homepage: https://github.com/locaweb/ruby-simplestack-client
51
69
  licenses: []
52
70
  metadata: {}