clouddb 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 +3 -0
- data/COPYING +12 -0
- data/README.rdoc +45 -0
- data/clouddb.gemspec +38 -0
- data/lib/clouddb.rb +98 -0
- data/lib/clouddb/authentication.rb +36 -0
- data/lib/clouddb/connection.rb +224 -0
- data/lib/clouddb/database.rb +27 -0
- data/lib/clouddb/exception.rb +73 -0
- data/lib/clouddb/flavor.rb +36 -0
- data/lib/clouddb/instance.rb +244 -0
- data/lib/clouddb/user.rb +27 -0
- data/lib/clouddb/version.rb +3 -0
- metadata +95 -0
data/.gitignore
ADDED
data/COPYING
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Unless otherwise noted, all files are released under the MIT license, exceptions contain licensing information in them.
|
2
|
+
|
3
|
+
Copyright (C) 2012 Rackspace US, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
10
|
+
|
11
|
+
Except as contained in this notice, the name of Rackspace US, Inc. shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Rackspace US, Inc.
|
12
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
= Rackspace Cloud Databases
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
This is a Ruby interface into the Rackspace[http://rackspace.com/] {Cloud Databases}[http://www.rackspace.com/blog/announcing-the-rackspace-mysql-cloud-database-private-beta/] service.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
This source is available on Github[http://github.com/rackspace/ruby-clouddb/] and the gem is available on RubyGems[http://rubygems.org/] (coming soon..). To install it, do
|
10
|
+
|
11
|
+
sudo gem install clouddb
|
12
|
+
|
13
|
+
To use it in Bundler, add the following statement to your Gemfile
|
14
|
+
|
15
|
+
gem "clouddb"
|
16
|
+
|
17
|
+
== RDOC Documentation
|
18
|
+
|
19
|
+
Find the latest RDoc documentation for this library at http://rdoc.info/github/rackspace/ruby-clouddb/master/frames
|
20
|
+
|
21
|
+
== API Documentation
|
22
|
+
|
23
|
+
This binding attempts to conform to the latest API specifications. For current API documentation, visit http://docs.rackspacecloud.com/api/
|
24
|
+
|
25
|
+
== Examples
|
26
|
+
|
27
|
+
See the class definitions for documentation on specific methods and operations.
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'clouddb'
|
31
|
+
|
32
|
+
# Authenticate to the Rackspace Cloud, and choose to manage databases in the Dallas/Ft. Worth datacenter
|
33
|
+
dbaas = CloudDB::Connection.new(:username => "MY_USERNAME", :api_key => "MY_API_KEY", :region => :dfw)
|
34
|
+
|
35
|
+
== Authors
|
36
|
+
|
37
|
+
{Jorge Miramontes}[https://github.com/jorgem1106/] <jorge.miramontes@rackspace.com>
|
38
|
+
{H. Wade Minter}[https://github.com/minter/] <minter@lunenburg.org>
|
39
|
+
|
40
|
+
== License
|
41
|
+
|
42
|
+
See COPYING for license information.
|
43
|
+
Copyright (c) 2012, Rackspace US, Inc.
|
44
|
+
|
45
|
+
|
data/clouddb.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include?(lib)
|
4
|
+
|
5
|
+
require File.expand_path('../lib/clouddb/version.rb', __FILE__)
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "clouddb"
|
9
|
+
s.version = CloudDB::VERSION
|
10
|
+
s.platform = Gem::Platform::RUBY
|
11
|
+
s.authors = %w("Jorge Miramontes", "H. Wade Minter")
|
12
|
+
s.email = %w(jorge.miramontes@rackspace.com minter@lunenburg.org)
|
13
|
+
s.homepage = "http://github.com/rackspace/ruby-clouddb"
|
14
|
+
s.summary = "Ruby API into the Rackspace Cloud Databases product"
|
15
|
+
s.description = "A Ruby API to manage the Rackspace Cloud Databases product"
|
16
|
+
|
17
|
+
s.required_rubygems_version = ">= 1.3.6"
|
18
|
+
|
19
|
+
s.add_runtime_dependency "typhoeus"
|
20
|
+
s.add_runtime_dependency "json"
|
21
|
+
|
22
|
+
s.files = [
|
23
|
+
"COPYING",
|
24
|
+
".gitignore",
|
25
|
+
"README.rdoc",
|
26
|
+
"clouddb.gemspec",
|
27
|
+
"lib/clouddb.rb",
|
28
|
+
"lib/clouddb/authentication.rb",
|
29
|
+
"lib/clouddb/flavor.rb",
|
30
|
+
"lib/clouddb/instance.rb",
|
31
|
+
"lib/clouddb/database.rb",
|
32
|
+
"lib/clouddb/user.rb",
|
33
|
+
"lib/clouddb/connection.rb",
|
34
|
+
"lib/clouddb/exception.rb",
|
35
|
+
"lib/clouddb/version.rb"
|
36
|
+
]
|
37
|
+
s.require_path = 'lib'
|
38
|
+
end
|
data/lib/clouddb.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# == Cloud Databases API
|
4
|
+
# ==== Connects Ruby Applications to Rackspace's {Cloud Databases service}[http://www.rackspace.com/cloud/cloud_hosting_products/databases/]
|
5
|
+
# By Jorge Miramontes <jorge.miramontes@rackspace.com> and H. Wade Minter <minter@lunenburg.org>
|
6
|
+
#
|
7
|
+
# See COPYING for license information.
|
8
|
+
# Copyright (c) 2012, Rackspace US, Inc.
|
9
|
+
# ----
|
10
|
+
#
|
11
|
+
# === Documentation & Examples
|
12
|
+
# To begin reviewing the available methods and examples, peruse the README.rodc file, or begin by looking at documentation for the
|
13
|
+
# CloudDB::Connection class.
|
14
|
+
#
|
15
|
+
# The CloudDB class is the base class. Not much of note aside from housekeeping happens here.
|
16
|
+
# To create a new CloudDB connection, use the CloudDB::Connection.new method.
|
17
|
+
|
18
|
+
module CloudDB
|
19
|
+
|
20
|
+
AUTH_USA = "https://auth.api.rackspacecloud.com/v1.0"
|
21
|
+
AUTH_UK = "https://lon.auth.api.rackspacecloud.com/v1.0"
|
22
|
+
|
23
|
+
require 'uri'
|
24
|
+
require 'rubygems'
|
25
|
+
require 'json'
|
26
|
+
require 'date'
|
27
|
+
require 'typhoeus'
|
28
|
+
|
29
|
+
unless "".respond_to? :each_char
|
30
|
+
require "jcode"
|
31
|
+
$KCODE = 'u'
|
32
|
+
end
|
33
|
+
|
34
|
+
$:.unshift(File.dirname(__FILE__))
|
35
|
+
require 'clouddb/version'
|
36
|
+
require 'clouddb/exception'
|
37
|
+
require 'clouddb/authentication'
|
38
|
+
require 'clouddb/connection'
|
39
|
+
require 'clouddb/flavor'
|
40
|
+
require 'clouddb/instance'
|
41
|
+
require 'clouddb/database'
|
42
|
+
require 'clouddb/user'
|
43
|
+
|
44
|
+
# Helper method to recursively symbolize hash keys.
|
45
|
+
def self.symbolize_keys(obj)
|
46
|
+
case obj
|
47
|
+
when Array
|
48
|
+
obj.inject([]){|res, val|
|
49
|
+
res << case val
|
50
|
+
when Hash, Array
|
51
|
+
symbolize_keys(val)
|
52
|
+
else
|
53
|
+
val
|
54
|
+
end
|
55
|
+
res
|
56
|
+
}
|
57
|
+
when Hash
|
58
|
+
obj.inject({}){|res, (key, val)|
|
59
|
+
nkey = case key
|
60
|
+
when String
|
61
|
+
key.to_sym
|
62
|
+
else
|
63
|
+
key
|
64
|
+
end
|
65
|
+
nval = case val
|
66
|
+
when Hash, Array
|
67
|
+
symbolize_keys(val)
|
68
|
+
else
|
69
|
+
val
|
70
|
+
end
|
71
|
+
res[nkey] = nval
|
72
|
+
res
|
73
|
+
}
|
74
|
+
else
|
75
|
+
obj
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.hydra
|
80
|
+
@@hydra ||= Typhoeus::Hydra.new
|
81
|
+
end
|
82
|
+
|
83
|
+
# CGI.escape, but without special treatment on spaces
|
84
|
+
def self.escape(str,extra_exclude_chars = '')
|
85
|
+
str.gsub(/([^a-zA-Z0-9_.-#{extra_exclude_chars}]+)/) do
|
86
|
+
'%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.paginate(options = {})
|
91
|
+
path_args = []
|
92
|
+
path_args.push(URI.encode("limit=#{options[:limit]}")) if options[:limit]
|
93
|
+
path_args.push(URI.encode("offset=#{options[:offset]}")) if options[:offset]
|
94
|
+
path_args.join("&")
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CloudDB
|
2
|
+
class Authentication
|
3
|
+
|
4
|
+
# Performs an authentication to the Rackspace Cloud authorization servers. Opens a new HTTP connection to the API server,
|
5
|
+
# sends the credentials, and looks for a successful authentication. If it succeeds, it sets the svrmgmthost,
|
6
|
+
# svrmgtpath, svrmgmtport, svrmgmtscheme, authtoken, and authok variables on the connection. If it fails, it raises
|
7
|
+
# an exception.
|
8
|
+
#
|
9
|
+
# Should probably never be called directly.
|
10
|
+
def initialize(connection)
|
11
|
+
request = Typhoeus::Request.new(connection.auth_url,
|
12
|
+
:method => :get,
|
13
|
+
:headers => { "X-Auth-User" => connection.authuser, "X-Auth-Key" => connection.authkey, "User-Agent" => "Cloud Databases Ruby API #{VERSION}" },
|
14
|
+
:verbose => ENV['DATABASES_VERBOSE'] ? true : false)
|
15
|
+
CloudDB.hydra.queue(request)
|
16
|
+
CloudDB.hydra.run
|
17
|
+
response = request.response
|
18
|
+
headers = response.headers_hash
|
19
|
+
if (response.code.to_s == "204")
|
20
|
+
connection.authtoken = headers["x-auth-token"]
|
21
|
+
user_id = headers["x-server-management-url"].match(/.*\/(\d+)$/)[1]
|
22
|
+
headers["x-server-management-url"] = "https://#{connection.region}.databases.api.rackspacecloud.com/v1.0/#{user_id}"
|
23
|
+
connection.dbmgmthost = URI.parse(headers["x-server-management-url"]).host
|
24
|
+
connection.dbmgmtpath = URI.parse(headers["x-server-management-url"]).path.chomp
|
25
|
+
# Force the path into the v1.0 URL space
|
26
|
+
connection.dbmgmtpath.sub!(/\/.*?\//, '/v1.0/')
|
27
|
+
connection.dbmgmtport = URI.parse(headers["x-server-management-url"]).port
|
28
|
+
connection.dbmgmtscheme = URI.parse(headers["x-server-management-url"]).scheme
|
29
|
+
connection.authok = true
|
30
|
+
else
|
31
|
+
connection.authtoken = false
|
32
|
+
raise CloudDB::Exception::Authentication, "Authentication failed with response code #{response.code}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
module CloudDB
|
2
|
+
class Connection
|
3
|
+
|
4
|
+
attr_reader :authuser
|
5
|
+
attr_reader :authkey
|
6
|
+
attr_accessor :authtoken
|
7
|
+
attr_accessor :authok
|
8
|
+
attr_accessor :dbmgmthost
|
9
|
+
attr_accessor :dbmgmtpath
|
10
|
+
attr_accessor :dbmgmtport
|
11
|
+
attr_accessor :dbmgmtscheme
|
12
|
+
attr_reader :auth_url
|
13
|
+
attr_reader :region
|
14
|
+
|
15
|
+
# Creates a new CloudDB::Connection object. Uses CloudDB::Authentication to perform the login for the connection.
|
16
|
+
#
|
17
|
+
# Setting the retry_auth option to false will cause an exception to be thrown if your authorization token expires.
|
18
|
+
# Otherwise, it will attempt to re-authenticate.
|
19
|
+
#
|
20
|
+
# This will likely be the base class for most operations.
|
21
|
+
#
|
22
|
+
# The constructor takes a hash of options, including:
|
23
|
+
# :username - Your Rackspace Cloud username *required*
|
24
|
+
# :api_key - Your Rackspace Cloud API key *required*
|
25
|
+
# :region - The region in which to manage database instances. Current options are :dfw (Rackspace Dallas/Ft. Worth
|
26
|
+
# Datacenter), :ord (Rackspace Chicago Datacenter) and :lon (Rackspace London Datacenter). *required*
|
27
|
+
# :auth_url - The URL to use for authentication. (defaults to Rackspace USA).
|
28
|
+
# :retry_auth - Whether to retry if your auth token expires (defaults to true)
|
29
|
+
#
|
30
|
+
# Example:
|
31
|
+
# dbaas = CloudDB::Connection.new(:username => 'YOUR_USERNAME', :api_key => 'YOUR_API_KEY', :region => :dfw)
|
32
|
+
def initialize(options = {:retry_auth => true})
|
33
|
+
@authuser = options[:username] || (raise CloudDB::Exception::Authentication, "Must supply a :username")
|
34
|
+
@authkey = options[:api_key] || (raise CloudDB::Exception::Authentication, "Must supply an :api_key")
|
35
|
+
@region = options[:region] || (raise CloudDB::Exception::Authentication, "Must supply a :region")
|
36
|
+
@retry_auth = options[:retry_auth]
|
37
|
+
@auth_url = options[:auth_url] || CloudDB::AUTH_USA
|
38
|
+
@snet = ENV['RACKSPACE_SERVICENET'] || options[:snet]
|
39
|
+
@authok = false
|
40
|
+
@http = {}
|
41
|
+
CloudDB::Authentication.new(self)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns true if the authentication was successful and returns false otherwise.
|
45
|
+
#
|
46
|
+
# Example:
|
47
|
+
# dbaas.authok?
|
48
|
+
# => true
|
49
|
+
def authok?
|
50
|
+
@authok
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the list of available database instances.
|
54
|
+
#
|
55
|
+
# Information returned includes:
|
56
|
+
# :id - The numeric id of the instance.
|
57
|
+
# :name - The name of the instance.
|
58
|
+
# :status - The current state of the instance (BUILD, ACTIVE, BLOCKED, RESIZE, SHUTDOWN, FAILED).
|
59
|
+
def list_instances()
|
60
|
+
response = dbreq("GET", dbmgmthost, "#{dbmgmtpath}/instances", dbmgmtport, dbmgmtscheme)
|
61
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
62
|
+
instances = CloudDB.symbolize_keys(JSON.parse(response.body)["instances"])
|
63
|
+
return instances
|
64
|
+
end
|
65
|
+
alias :instances :list_instances
|
66
|
+
|
67
|
+
# Returns the list of available database instances with detail.
|
68
|
+
#
|
69
|
+
# Information returned includes:
|
70
|
+
# :id - The numeric ID of the instance.
|
71
|
+
# :name - The name of the instance.
|
72
|
+
# :status - The current state of the instance (BUILD, ACTIVE, BLOCKED, RESIZE, SHUTDOWN, FAILED).
|
73
|
+
# :hostname - A DNS-resolvable hostname associated with the database instance.
|
74
|
+
# :flavor - The flavor of the instance.
|
75
|
+
# :volume - The volume size of the instance.
|
76
|
+
# :created - The time when the instance was created.
|
77
|
+
# :updated - The time when the instance was last updated.
|
78
|
+
def list_instances_detail()
|
79
|
+
response = dbreq("GET", dbmgmthost, "#{dbmgmtpath}/instances/detail", dbmgmtport, dbmgmtscheme)
|
80
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
81
|
+
instances = CloudDB.symbolize_keys(JSON.parse(response.body)["instances"])
|
82
|
+
return instances
|
83
|
+
end
|
84
|
+
alias :instances_detail :list_instances_detail
|
85
|
+
|
86
|
+
# Returns a CloudDB::Instance object for the given instance ID number.
|
87
|
+
#
|
88
|
+
# Example:
|
89
|
+
# dbaas.get_instance(692d8418-7a8f-47f1-8060-59846c6e024f)
|
90
|
+
def get_instance(id)
|
91
|
+
CloudDB::Instance.new(self,id)
|
92
|
+
end
|
93
|
+
alias :instance :get_instance
|
94
|
+
|
95
|
+
# Creates a brand new database instance under your account.
|
96
|
+
#
|
97
|
+
# Options:
|
98
|
+
# :flavor_ref - reference to a flavor as specified in the response from the List Flavors API call. *required*
|
99
|
+
# :name - the name of the database instance. Limited to 128 characters or less. *required*
|
100
|
+
# :size - specifies the volume size in gigabytes (GB). The value specified must be between 1 and 10. *required*
|
101
|
+
# :databases - the databases to be created for the instance.
|
102
|
+
# :users - the users to be created for the instance.
|
103
|
+
#
|
104
|
+
# Example:
|
105
|
+
# i = dbaas.create_instance(:flavor_ref => "https://ord.databases.api.rackspacecloud.com/v1.0/1234/flavors/1",
|
106
|
+
# :name => "test_instance",
|
107
|
+
# :volume => {:size => "1"},
|
108
|
+
# :databases => [{:name => "testdb"}],
|
109
|
+
# :users => [{:name => "test",
|
110
|
+
# :password => "test",
|
111
|
+
# :databases => [{:name => "testdb"}]}
|
112
|
+
# ]
|
113
|
+
# )
|
114
|
+
def create_instance(options = {})
|
115
|
+
body = Hash.new
|
116
|
+
body[:instance] = Hash.new
|
117
|
+
|
118
|
+
body[:instance][:flavorRef] = options[:flavor_ref] or raise CloudDB::Exception::MissingArgument, "Must provide a flavor to create an instance"
|
119
|
+
body[:instance][:name] = options[:name] or raise CloudDB::Exception::MissingArgument, "Must provide a name to create an instance"
|
120
|
+
body[:instance][:volume] = options[:volume] or raise CloudDB::Exception::MissingArgument, "Must provide a size to create an instance"
|
121
|
+
body[:instance][:databases] = options[:databases] if options[:databases]
|
122
|
+
body[:instance][:users] = options[:users] if options[:users]
|
123
|
+
(raise CloudDB::Exception::Syntax, "Instance name must be 128 characters or less") if options[:name].size > 128
|
124
|
+
|
125
|
+
response = dbreq("POST", dbmgmthost, "#{dbmgmtpath}/instances", dbmgmtport, dbmgmtscheme, {}, body.to_json)
|
126
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
127
|
+
body = JSON.parse(response.body)['instance']
|
128
|
+
return get_instance(body["id"])
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns the list of available database flavors.
|
132
|
+
#
|
133
|
+
# Information returned includes:
|
134
|
+
# :id - The numeric id of this flavor
|
135
|
+
# :name - The name of the flavor
|
136
|
+
# :links - Useful information regarding the flavor
|
137
|
+
def list_flavors()
|
138
|
+
response = dbreq("GET", dbmgmthost, "#{dbmgmtpath}/flavors", dbmgmtport, dbmgmtscheme)
|
139
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
140
|
+
flavors = CloudDB.symbolize_keys(JSON.parse(response.body)["flavors"])
|
141
|
+
return flavors
|
142
|
+
end
|
143
|
+
alias :flavors :list_flavors
|
144
|
+
|
145
|
+
# Returns the list of available database flavors in detail.
|
146
|
+
#
|
147
|
+
# Information returned includes:
|
148
|
+
# :id - The numeric id of this flavor
|
149
|
+
# :name - The name of the flavor
|
150
|
+
# :vcpus - The amount of virtual cpu power
|
151
|
+
# :ram - The available memory in MB
|
152
|
+
# :links - Useful information regarding the flavor
|
153
|
+
def list_flavors_detail()
|
154
|
+
response = dbreq("GET", dbmgmthost, "#{dbmgmtpath}/flavors/detail", dbmgmtport, dbmgmtscheme)
|
155
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
156
|
+
flavors = CloudDB.symbolize_keys(JSON.parse(response.body)["flavors"])
|
157
|
+
return flavors
|
158
|
+
end
|
159
|
+
alias :flavors_detail :list_flavors_detail
|
160
|
+
|
161
|
+
# Returns a CloudDB::Flavor object for the given flavor id number.
|
162
|
+
#
|
163
|
+
# Example:
|
164
|
+
# dbaas.get_flavor(3)
|
165
|
+
def get_flavor(id)
|
166
|
+
CloudDB::Flavor.new(self,id)
|
167
|
+
end
|
168
|
+
alias :flavor :get_flavor
|
169
|
+
|
170
|
+
# This method actually makes the HTTP REST calls out to the server. Relies on the thread-safe typhoeus
|
171
|
+
# gem to do the heavy lifting. Never called directly.
|
172
|
+
def dbreq(method, server, path, port, scheme, headers = {}, data = nil, attempts = 0) # :nodoc:
|
173
|
+
if data
|
174
|
+
unless data.is_a?(IO)
|
175
|
+
headers['Content-Length'] = data.respond_to?(:lstat) ? data.stat.size : data.size
|
176
|
+
end
|
177
|
+
else
|
178
|
+
headers['Content-Length'] = 0
|
179
|
+
end
|
180
|
+
hdrhash = headerprep(headers)
|
181
|
+
url = "#{scheme}://#{server}#{path}"
|
182
|
+
print "DEBUG: Data is #{data}\n" if (data && ENV['DATABASES_VERBOSE'])
|
183
|
+
request = Typhoeus::Request.new(url,
|
184
|
+
:body => data,
|
185
|
+
:method => method.downcase.to_sym,
|
186
|
+
:headers => hdrhash,
|
187
|
+
:verbose => ENV['DATABASES_VERBOSE'] ? true : false)
|
188
|
+
CloudDB.hydra.queue(request)
|
189
|
+
CloudDB.hydra.run
|
190
|
+
|
191
|
+
response = request.response
|
192
|
+
print "DEBUG: Body is #{response.body}\n" if ENV['DATABASES_VERBOSE']
|
193
|
+
raise CloudDB::Exception::ExpiredAuthToken if response.code.to_s == "401"
|
194
|
+
response
|
195
|
+
rescue Errno::EPIPE, Errno::EINVAL, EOFError
|
196
|
+
# Server closed the connection, retry
|
197
|
+
raise CloudDB::Exception::Connection, "Unable to reconnect to #{server} after #{attempts} attempts" if attempts >= 5
|
198
|
+
attempts += 1
|
199
|
+
@http[server].finish if @http[server].started?
|
200
|
+
start_http(server,path,port,scheme,headers)
|
201
|
+
retry
|
202
|
+
rescue CloudDB::Exception::ExpiredAuthToken
|
203
|
+
raise CloudDB::Exception::Connection, "Authentication token expired and you have requested not to retry" if @retry_auth == false
|
204
|
+
CloudDB::Authentication.new(self)
|
205
|
+
retry
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
# Sets up standard HTTP headers
|
212
|
+
def headerprep(headers = {}) # :nodoc:
|
213
|
+
default_headers = {}
|
214
|
+
default_headers["X-Auth-Token"] = @authtoken if (authok? && @account.nil?)
|
215
|
+
default_headers["X-Storage-Token"] = @authtoken if (authok? && !@account.nil?)
|
216
|
+
default_headers["Connection"] = "Keep-Alive"
|
217
|
+
default_headers["Accept"] = "application/json"
|
218
|
+
default_headers["Content-Type"] = "application/json"
|
219
|
+
default_headers["User-Agent"] = "Cloud Databases Ruby API #{CloudDB::VERSION}"
|
220
|
+
default_headers.merge(headers)
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module CloudDB
|
2
|
+
class Database
|
3
|
+
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
# Creates a new CloudDB::Database object representing a database.
|
7
|
+
def initialize(instance, name)
|
8
|
+
@connection = instance.connection
|
9
|
+
@instance = instance
|
10
|
+
@name = name
|
11
|
+
@dbmgmthost = @connection.dbmgmthost
|
12
|
+
@dbmgmtpath = @connection.dbmgmtpath
|
13
|
+
@dbmgmtport = @connection.dbmgmtport
|
14
|
+
@dbmgmtscheme = @connection.dbmgmtscheme
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Deletes the current Database object and removes it from the instance. Returns true if successful, raises an
|
19
|
+
# exception if not.
|
20
|
+
def destroy!
|
21
|
+
response = @connection.dbreq("DELETE",@dbmgmthost,"#{@dbmgmtpath}/instances/#{CloudDB.escape(@instance.id.to_s)}/databases/#{CloudDB.escape(@name.to_s)}",@dbmgmtport,@dbmgmtscheme)
|
22
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module CloudDB
|
2
|
+
class Exception
|
3
|
+
|
4
|
+
class CloudDBError < StandardError
|
5
|
+
|
6
|
+
attr_reader :response_body
|
7
|
+
attr_reader :response_code
|
8
|
+
|
9
|
+
def initialize(message, code, response_body)
|
10
|
+
@response_code=code
|
11
|
+
@response_body=response_body
|
12
|
+
super(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class ServiceFault < CloudDBError # :nodoc:
|
18
|
+
end
|
19
|
+
class InstanceFault < CloudDBError # :nodoc:
|
20
|
+
end
|
21
|
+
class ServiceUnavailable < CloudDBError # :nodoc:
|
22
|
+
end
|
23
|
+
class Unauthorized < CloudDBError # :nodoc:
|
24
|
+
end
|
25
|
+
class BadRequest < CloudDBError # :nodoc:
|
26
|
+
end
|
27
|
+
class ItemNotFound < CloudDBError # :nodoc:
|
28
|
+
end
|
29
|
+
class OverLimit < CloudDBError # :nodoc:
|
30
|
+
end
|
31
|
+
class ImmutableEntity < CloudDBError # :nodoc:
|
32
|
+
end
|
33
|
+
class UnprocessableEntity < CloudDBError # :nodoc:
|
34
|
+
end
|
35
|
+
class Other < CloudDBError # :nodoc:
|
36
|
+
end
|
37
|
+
|
38
|
+
# Plus some others that we define here
|
39
|
+
|
40
|
+
class ExpiredAuthToken < StandardError # :nodoc:
|
41
|
+
end
|
42
|
+
class MissingArgument < StandardError # :nodoc:
|
43
|
+
end
|
44
|
+
class Authentication < StandardError # :nodoc:
|
45
|
+
end
|
46
|
+
class Connection < StandardError # :nodoc:
|
47
|
+
end
|
48
|
+
class Syntax < StandardError # :nodoc:
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# In the event of a non-200 HTTP status code, this method takes the HTTP response, parses
|
53
|
+
# the JSON from the body to get more information about the exception, then raises the
|
54
|
+
# proper error. Note that all exceptions are scoped in the CloudDB::Exception namespace.
|
55
|
+
def self.raise_exception(response)
|
56
|
+
return if response.code =~ /^20.$/
|
57
|
+
begin
|
58
|
+
fault = nil
|
59
|
+
info = nil
|
60
|
+
JSON.parse(response.body).each_pair do |key, val|
|
61
|
+
fault=key
|
62
|
+
info=val
|
63
|
+
end
|
64
|
+
exception_class = self.const_get(fault[0,1].capitalize+fault[1,fault.length])
|
65
|
+
raise exception_class.new(info["message"], response.code, response.body)
|
66
|
+
rescue NameError, JSON::ParserError
|
67
|
+
raise CloudDB::Exception::Other.new("The server returned status #{response.code} with body #{response.body}", response.code, response.body)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module CloudDB
|
2
|
+
class Flavor
|
3
|
+
|
4
|
+
attr_reader :id
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :ram
|
7
|
+
attr_reader :vcpus
|
8
|
+
|
9
|
+
# Creates a new CloudDB::Flavor object representing a database flavor.
|
10
|
+
def initialize(connection,id)
|
11
|
+
@connection = connection
|
12
|
+
@id = id
|
13
|
+
@dbmgmthost = connection.dbmgmthost
|
14
|
+
@dbmgmtpath = connection.dbmgmtpath
|
15
|
+
@dbmgmtport = connection.dbmgmtport
|
16
|
+
@dbmgmtscheme = connection.dbmgmtscheme
|
17
|
+
populate
|
18
|
+
return self
|
19
|
+
end
|
20
|
+
|
21
|
+
# Updates the information about the current Flavor object by making an API call.
|
22
|
+
def populate
|
23
|
+
response = @connection.dbreq("GET",@dbmgmthost,"#{@dbmgmtpath}/flavors/#{CloudDB.escape(@id.to_s)}",@dbmgmtport,@dbmgmtscheme)
|
24
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
25
|
+
data = JSON.parse(response.body)['flavor']
|
26
|
+
@id = data["id"]
|
27
|
+
@name = data["name"]
|
28
|
+
@ram = data["ram"]
|
29
|
+
@vcpus = data["vcpus"]
|
30
|
+
@links = data["links"]
|
31
|
+
true
|
32
|
+
end
|
33
|
+
alias :refresh :populate
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
module CloudDB
|
2
|
+
class Instance
|
3
|
+
|
4
|
+
attr_reader :connection
|
5
|
+
|
6
|
+
attr_reader :id
|
7
|
+
attr_reader :name
|
8
|
+
attr_reader :hostname
|
9
|
+
attr_reader :flavor_id
|
10
|
+
attr_reader :root_enabled
|
11
|
+
attr_reader :volume_used
|
12
|
+
attr_reader :volume_size
|
13
|
+
attr_reader :status
|
14
|
+
attr_reader :created
|
15
|
+
attr_reader :updated
|
16
|
+
attr_reader :links
|
17
|
+
|
18
|
+
# Creates a new CloudDB::Instance object representing a database instance.
|
19
|
+
def initialize(connection,id)
|
20
|
+
@connection = connection
|
21
|
+
@id = id
|
22
|
+
@dbmgmthost = connection.dbmgmthost
|
23
|
+
@dbmgmtpath = connection.dbmgmtpath
|
24
|
+
@dbmgmtport = connection.dbmgmtport
|
25
|
+
@dbmgmtscheme = connection.dbmgmtscheme
|
26
|
+
populate
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# Updates the information about the current instance object by making an API call.
|
31
|
+
def populate
|
32
|
+
response = @connection.dbreq("GET", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}", @dbmgmtport, @dbmgmtscheme)
|
33
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
34
|
+
data = JSON.parse(response.body)['instance']
|
35
|
+
@id = data["id"]
|
36
|
+
@name = data["name"]
|
37
|
+
@hostname = data["hostname"]
|
38
|
+
@flavor_id = data["flavor"]["id"] if data["flavor"]
|
39
|
+
@root_enabled = data["rootEnabled"]
|
40
|
+
@volume_used = data["volume"]["used"] if data["volume"]
|
41
|
+
@volume_size = data["volume"]["size"] if data["volume"]
|
42
|
+
@status = data["status"]
|
43
|
+
@created = data["created"]
|
44
|
+
@updated = data["updated"]
|
45
|
+
@links = data["links"]
|
46
|
+
true
|
47
|
+
end
|
48
|
+
alias :refresh :populate
|
49
|
+
|
50
|
+
# Lists the databases associated with this instance
|
51
|
+
#
|
52
|
+
# Example:
|
53
|
+
# i.list_databases
|
54
|
+
def list_databases
|
55
|
+
response = @connection.dbreq("GET", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/databases", @dbmgmtport, @dbmgmtscheme)
|
56
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
57
|
+
CloudDB.symbolize_keys(JSON.parse(response.body)["databases"])
|
58
|
+
end
|
59
|
+
alias :databases :list_databases
|
60
|
+
|
61
|
+
# Returns a CloudDB::Database object for the given database name.
|
62
|
+
def get_database(name)
|
63
|
+
CloudDB::Database.new(self, name)
|
64
|
+
end
|
65
|
+
alias :database :get_database
|
66
|
+
|
67
|
+
# Creates brand new databases and associates them with the current instance. Returns true if successful.
|
68
|
+
#
|
69
|
+
# Options for each database in the array:
|
70
|
+
# :name - Specifies the database name for creating the database. *required*
|
71
|
+
# :character_set - Set of symbols and encodings. The default character set is utf8.
|
72
|
+
# :collate - Set of rules for comparing characters in a character set. The default value for collate is
|
73
|
+
# utf8_general_ci.
|
74
|
+
def create_databases(databases)
|
75
|
+
(raise CloudDB::Exception::Syntax, "Must provide at least one database in the array") if (!databases.is_a?(Array) || databases.size < 1)
|
76
|
+
|
77
|
+
body = Hash.new
|
78
|
+
body[:databases] = Array.new
|
79
|
+
|
80
|
+
for database in databases
|
81
|
+
new_database = Hash.new
|
82
|
+
new_database[:name] = database[:name] or raise CloudDB::Exception::MissingArgument, "Must provide a name for each database"
|
83
|
+
new_database[:character_set] = database[:character_set] || 'utf8'
|
84
|
+
new_database[:collate] = database[:collate] || 'utf8_general_ci'
|
85
|
+
(raise CloudDB::Exception::Syntax, "Database names must be 64 characters or less") if database[:name].size > 64
|
86
|
+
|
87
|
+
body[:databases] << new_database
|
88
|
+
end
|
89
|
+
|
90
|
+
response = @connection.dbreq("POST", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/databases", @dbmgmtport, @dbmgmtscheme, {}, body.to_json)
|
91
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
# Creates a brand new database and associates it with the current instance. Returns true if successful.
|
96
|
+
#
|
97
|
+
# Options:
|
98
|
+
# :name - Specifies the database name for creating the database. *required*
|
99
|
+
# :character_set - Set of symbols and encodings. The default character set is utf8.
|
100
|
+
# :collate - Set of rules for comparing characters in a character set. The default value for collate is
|
101
|
+
# utf8_general_ci.
|
102
|
+
def create_database(options={})
|
103
|
+
new_databases = Array.new
|
104
|
+
new_databases << options
|
105
|
+
create_databases new_databases
|
106
|
+
end
|
107
|
+
|
108
|
+
# Lists the users associated with the current Instance
|
109
|
+
#
|
110
|
+
# Example:
|
111
|
+
# i.list_users
|
112
|
+
def list_users
|
113
|
+
response = @connection.dbreq("GET", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/users", @dbmgmtport, @dbmgmtscheme)
|
114
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
115
|
+
CloudDB.symbolize_keys(JSON.parse(response.body)["users"])
|
116
|
+
end
|
117
|
+
alias :users :list_users
|
118
|
+
|
119
|
+
# Returns a CloudDB::User object for the given user name.
|
120
|
+
def get_user(name)
|
121
|
+
CloudDB::User.new(self, name)
|
122
|
+
end
|
123
|
+
alias :user :get_user
|
124
|
+
|
125
|
+
# Creates brand new users and associates them with the current instance. Returns true if successful.
|
126
|
+
#
|
127
|
+
# Options for each user in the array:
|
128
|
+
# :name - Name of the user for the database(s). *required*
|
129
|
+
# :password - User password for database access. *required*
|
130
|
+
# :databases - An array of databases with at least one database. *required*
|
131
|
+
def create_users(users)
|
132
|
+
(raise CloudDB::Exception::Syntax, "Must provide at least one user in the array") if (!users.is_a?(Array) || users.size < 1)
|
133
|
+
|
134
|
+
body = Hash.new
|
135
|
+
body[:users] = Array.new
|
136
|
+
|
137
|
+
for user in users
|
138
|
+
new_user = Hash.new
|
139
|
+
new_user[:name] = user[:name] or raise CloudDB::Exception::MissingArgument, "Must provide a name for each user"
|
140
|
+
new_user[:password] = user[:password] or raise CloudDB::Exception::MissingArgument, "Must provide a password for each user"
|
141
|
+
new_user[:databases] = user[:databases]
|
142
|
+
(raise CloudDB::Exception::Syntax, "User names must be 16 characters or less") if user[:name].size > 16
|
143
|
+
(raise CloudDB::Exception::Syntax, "Must provide at least one database in each user :databases array") if (!user[:databases].is_a?(Array) || user[:databases].size < 1)
|
144
|
+
|
145
|
+
body[:users] << new_user
|
146
|
+
end
|
147
|
+
|
148
|
+
response = @connection.dbreq("POST", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/users", @dbmgmtport, @dbmgmtscheme, {}, body.to_json)
|
149
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
153
|
+
# Creates a brand new user and associates it with the current instance. Returns true if successful.
|
154
|
+
#
|
155
|
+
# Options:
|
156
|
+
# :name - Name of the user for the database(s). *required*
|
157
|
+
# :password - User password for database access. *required*
|
158
|
+
# :databases - An array of databases with at least one database. *required*
|
159
|
+
def create_user(options={})
|
160
|
+
new_users = Array.new
|
161
|
+
new_users << options
|
162
|
+
create_users new_users
|
163
|
+
end
|
164
|
+
|
165
|
+
# Enables the root user for the specified database instance and returns the root password.
|
166
|
+
#
|
167
|
+
# Example:
|
168
|
+
# i.enable_root
|
169
|
+
# => true
|
170
|
+
def enable_root()
|
171
|
+
response = @connection.dbreq("POST", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/root", @dbmgmtport, @dbmgmtscheme, {})
|
172
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
173
|
+
@root_enabled = true
|
174
|
+
body = JSON.parse(response.body)['user']
|
175
|
+
return body
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns true if root user is enabled for the specified database instance or false otherwise.
|
179
|
+
#
|
180
|
+
# Example:
|
181
|
+
# i.root_enabled?
|
182
|
+
# => true
|
183
|
+
def root_enabled?()
|
184
|
+
response = @connection.dbreq("GET", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/root", @dbmgmtport, @dbmgmtscheme, {})
|
185
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
186
|
+
@root_enabled = JSON.parse(response.body)['rootEnabled']
|
187
|
+
return @root_enabled
|
188
|
+
end
|
189
|
+
|
190
|
+
# This operation changes the memory size of the instance, assuming a valid flavorRef is provided. Restarts MySQL in
|
191
|
+
# the process.
|
192
|
+
#
|
193
|
+
# Options:
|
194
|
+
# :flavor_ref - reference to a flavor as specified in the response from the List Flavors API call. *required*
|
195
|
+
def resize(options={})
|
196
|
+
body = Hash.new
|
197
|
+
body[:resize] = Hash.new
|
198
|
+
|
199
|
+
body[:resize][:flavorRef] = options[:flavor_ref] or raise CloudDB::Exception::MissingArgument, "Must provide a flavor to create an instance"
|
200
|
+
|
201
|
+
response = @connection.dbreq("POST", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/action", @dbmgmtport, @dbmgmtscheme, {}, body.to_json)
|
202
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
203
|
+
true
|
204
|
+
end
|
205
|
+
|
206
|
+
# This operation supports resizing the attached volume for an instance. It supports only increasing the volume size
|
207
|
+
# and does not support decreasing the size. The volume size is in gigabytes (GB) and must be an integer.
|
208
|
+
#
|
209
|
+
# Options:
|
210
|
+
# :size - specifies the volume size in gigabytes (GB). The value specified must be between 1 and 10. *required*
|
211
|
+
def resize_volume(options={})
|
212
|
+
body = Hash.new
|
213
|
+
body[:resize] = Hash.new
|
214
|
+
volume = Hash.new
|
215
|
+
body[:resize][:volume] = volume
|
216
|
+
|
217
|
+
volume[:size] = options[:size] or raise CloudDB::Exception::MissingArgument, "Must provide a volume size"
|
218
|
+
(raise CloudDB::Exception::Syntax, "Volume size must be a value between 1 and 10") if !options[:size].is_a?(Integer) || options[:size] < 1 || options[:size] > 10
|
219
|
+
|
220
|
+
response = @connection.dbreq("POST", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/action", @dbmgmtport, @dbmgmtscheme, {}, body.to_json)
|
221
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
222
|
+
true
|
223
|
+
end
|
224
|
+
|
225
|
+
# The restart operation will restart only the MySQL Instance. Restarting MySQL will erase any dynamic configuration
|
226
|
+
# settings that you have made within MySQL.
|
227
|
+
def restart()
|
228
|
+
body = Hash.new
|
229
|
+
body[:restart] = Hash.new
|
230
|
+
|
231
|
+
response = @connection.dbreq("POST", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}/action", @dbmgmtport, @dbmgmtscheme, {}, body.to_json)
|
232
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
233
|
+
true
|
234
|
+
end
|
235
|
+
|
236
|
+
# Deletes the current instance object. Returns true if successful, raises an exception otherwise.
|
237
|
+
def destroy!
|
238
|
+
response = @connection.dbreq("DELETE", @dbmgmthost, "#{@dbmgmtpath}/instances/#{CloudDB.escape(@id.to_s)}", @dbmgmtport, @dbmgmtscheme)
|
239
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^202$/)
|
240
|
+
true
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
end
|
data/lib/clouddb/user.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module CloudDB
|
2
|
+
class User
|
3
|
+
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
# Creates a new CloudDB::User object representing a database.
|
7
|
+
def initialize(instance, name)
|
8
|
+
@connection = instance.connection
|
9
|
+
@instance = instance
|
10
|
+
@name = name
|
11
|
+
@dbmgmthost = @connection.dbmgmthost
|
12
|
+
@dbmgmtpath = @connection.dbmgmtpath
|
13
|
+
@dbmgmtport = @connection.dbmgmtport
|
14
|
+
@dbmgmtscheme = @connection.dbmgmtscheme
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Deletes the current User object and removes it from the instance. Returns true if successful, raises an
|
19
|
+
# exception if not.
|
20
|
+
def destroy!
|
21
|
+
response = @connection.dbreq("DELETE",@dbmgmthost,"#{@dbmgmtpath}/instances/#{CloudDB.escape(@instance.id.to_s)}/users/#{CloudDB.escape(@name.to_s)}",@dbmgmtport,@dbmgmtscheme)
|
22
|
+
CloudDB::Exception.raise_exception(response) unless response.code.to_s.match(/^20.$/)
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: clouddb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- ! '"Jorge'
|
9
|
+
- Miramontes",
|
10
|
+
- ! '"H.'
|
11
|
+
- Wade
|
12
|
+
- Minter"
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
date: 2012-04-30 00:00:00.000000000 Z
|
17
|
+
dependencies:
|
18
|
+
- !ruby/object:Gem::Dependency
|
19
|
+
name: typhoeus
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
21
|
+
none: false
|
22
|
+
requirements:
|
23
|
+
- - ! '>='
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
type: :runtime
|
27
|
+
prerelease: false
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: json
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
type: :runtime
|
43
|
+
prerelease: false
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
description: A Ruby API to manage the Rackspace Cloud Databases product
|
51
|
+
email:
|
52
|
+
- jorge.miramontes@rackspace.com
|
53
|
+
- minter@lunenburg.org
|
54
|
+
executables: []
|
55
|
+
extensions: []
|
56
|
+
extra_rdoc_files: []
|
57
|
+
files:
|
58
|
+
- COPYING
|
59
|
+
- .gitignore
|
60
|
+
- README.rdoc
|
61
|
+
- clouddb.gemspec
|
62
|
+
- lib/clouddb.rb
|
63
|
+
- lib/clouddb/authentication.rb
|
64
|
+
- lib/clouddb/flavor.rb
|
65
|
+
- lib/clouddb/instance.rb
|
66
|
+
- lib/clouddb/database.rb
|
67
|
+
- lib/clouddb/user.rb
|
68
|
+
- lib/clouddb/connection.rb
|
69
|
+
- lib/clouddb/exception.rb
|
70
|
+
- lib/clouddb/version.rb
|
71
|
+
homepage: http://github.com/rackspace/ruby-clouddb
|
72
|
+
licenses: []
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 1.3.6
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 1.8.19
|
92
|
+
signing_key:
|
93
|
+
specification_version: 3
|
94
|
+
summary: Ruby API into the Rackspace Cloud Databases product
|
95
|
+
test_files: []
|