simple_stack 0.0.28 → 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.
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: {}