acquia-cloud 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 +7 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +20 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +98 -0
- data/LICENSE +19 -0
- data/README.md +32 -0
- data/Rakefile +66 -0
- data/acquia-cloud.gemspec +31 -0
- data/lib/acquia/cloud.rb +41 -0
- data/lib/acquia/cloud/api.rb +56 -0
- data/lib/acquia/cloud/database.rb +22 -0
- data/lib/acquia/cloud/entity.rb +19 -0
- data/lib/acquia/cloud/environment.rb +80 -0
- data/lib/acquia/cloud/errors.rb +8 -0
- data/lib/acquia/cloud/logs/source.rb +17 -0
- data/lib/acquia/cloud/logs/streamer.rb +147 -0
- data/lib/acquia/cloud/server.rb +62 -0
- data/lib/acquia/cloud/site.rb +73 -0
- data/lib/acquia/cloud/task.rb +62 -0
- data/lib/acquia/cloud/version.rb +5 -0
- metadata +149 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 76d413a96d61a55b3bdd919b882bb1c2a51344e7
|
|
4
|
+
data.tar.gz: a4d6543e4d1c4036c00b5fb9cbde78e2af438929
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 70a6e0594f9248b8ba6348bce0c041a0c2ad0e4df6a1bd60493c4ed844d8a9564f06aee35e741194405d52ad665b68eba826f34cf75f3752755c18ea7a247e37
|
|
7
|
+
data.tar.gz: 43c45cbc34be2a07f6745b9e2f40628b313645b2a8c8f66e1d9f12aa4da05ce98c2b188fdef947b34c9b8d11a1bd462944fc1c0a87aa392fd02de775bfc77dd5
|
data/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/pkg
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.2
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
acquia-cloud (0.1.0.pre)
|
|
5
|
+
faraday (~> 0.9)
|
|
6
|
+
websocket (~> 1.2)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
abstract_type (0.0.7)
|
|
12
|
+
adamantium (0.2.0)
|
|
13
|
+
ice_nine (~> 0.11.0)
|
|
14
|
+
memoizable (~> 0.4.0)
|
|
15
|
+
anima (0.3.0)
|
|
16
|
+
abstract_type (~> 0.0.7)
|
|
17
|
+
adamantium (~> 0.2)
|
|
18
|
+
equalizer (~> 0.0.11)
|
|
19
|
+
ast (2.1.0)
|
|
20
|
+
concord (0.1.5)
|
|
21
|
+
adamantium (~> 0.2.0)
|
|
22
|
+
equalizer (~> 0.0.9)
|
|
23
|
+
diff-lcs (1.2.5)
|
|
24
|
+
equalizer (0.0.11)
|
|
25
|
+
faraday (0.9.2)
|
|
26
|
+
multipart-post (>= 1.2, < 3)
|
|
27
|
+
ice_nine (0.11.1)
|
|
28
|
+
memoizable (0.4.2)
|
|
29
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
|
30
|
+
morpher (0.2.5)
|
|
31
|
+
abstract_type (~> 0.0.7)
|
|
32
|
+
adamantium (~> 0.2.0)
|
|
33
|
+
anima (~> 0.3.0)
|
|
34
|
+
ast (~> 2.1.0)
|
|
35
|
+
concord (~> 0.1.5)
|
|
36
|
+
equalizer (~> 0.0.9)
|
|
37
|
+
ice_nine (~> 0.11.0)
|
|
38
|
+
procto (~> 0.0.2)
|
|
39
|
+
multipart-post (2.0.0)
|
|
40
|
+
mutant (0.8.8)
|
|
41
|
+
abstract_type (~> 0.0.7)
|
|
42
|
+
adamantium (~> 0.2.0)
|
|
43
|
+
anima (~> 0.3.0)
|
|
44
|
+
ast (~> 2.1)
|
|
45
|
+
concord (~> 0.1.5)
|
|
46
|
+
diff-lcs (~> 1.2)
|
|
47
|
+
equalizer (~> 0.0.9)
|
|
48
|
+
ice_nine (~> 0.11.1)
|
|
49
|
+
memoizable (~> 0.4.2)
|
|
50
|
+
morpher (~> 0.2.5)
|
|
51
|
+
parallel (~> 1.3)
|
|
52
|
+
parser (~> 2.2.2)
|
|
53
|
+
procto (~> 0.0.2)
|
|
54
|
+
unparser (~> 0.2.4)
|
|
55
|
+
mutant-rspec (0.8.8)
|
|
56
|
+
mutant (~> 0.8.8)
|
|
57
|
+
rspec-core (>= 3.2.0, < 3.5.0)
|
|
58
|
+
parallel (1.6.1)
|
|
59
|
+
parser (2.2.3.0)
|
|
60
|
+
ast (>= 1.1, < 3.0)
|
|
61
|
+
procto (0.0.2)
|
|
62
|
+
rake (10.4.2)
|
|
63
|
+
rspec (3.4.0)
|
|
64
|
+
rspec-core (~> 3.4.0)
|
|
65
|
+
rspec-expectations (~> 3.4.0)
|
|
66
|
+
rspec-mocks (~> 3.4.0)
|
|
67
|
+
rspec-core (3.4.0)
|
|
68
|
+
rspec-support (~> 3.4.0)
|
|
69
|
+
rspec-expectations (3.4.0)
|
|
70
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
71
|
+
rspec-support (~> 3.4.0)
|
|
72
|
+
rspec-mocks (3.4.0)
|
|
73
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
74
|
+
rspec-support (~> 3.4.0)
|
|
75
|
+
rspec-support (3.4.0)
|
|
76
|
+
thread_safe (0.3.5)
|
|
77
|
+
unparser (0.2.4)
|
|
78
|
+
abstract_type (~> 0.0.7)
|
|
79
|
+
adamantium (~> 0.2.0)
|
|
80
|
+
concord (~> 0.1.5)
|
|
81
|
+
diff-lcs (~> 1.2.5)
|
|
82
|
+
equalizer (~> 0.0.9)
|
|
83
|
+
parser (~> 2.2.2)
|
|
84
|
+
procto (~> 0.0.2)
|
|
85
|
+
websocket (1.2.2)
|
|
86
|
+
|
|
87
|
+
PLATFORMS
|
|
88
|
+
ruby
|
|
89
|
+
|
|
90
|
+
DEPENDENCIES
|
|
91
|
+
acquia-cloud!
|
|
92
|
+
mutant (~> 0.8)
|
|
93
|
+
mutant-rspec (~> 0.8)
|
|
94
|
+
rake (~> 10.4)
|
|
95
|
+
rspec (~> 3.3)
|
|
96
|
+
|
|
97
|
+
BUNDLED WITH
|
|
98
|
+
1.10.6
|
data/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2015 Matthew Scharley
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
4
|
+
copy of this software and associated documentation files (the "Software"),
|
|
5
|
+
to deal in the Software without restriction, including without limitation
|
|
6
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
7
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
|
8
|
+
Software is furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included
|
|
11
|
+
in all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
14
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
16
|
+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
18
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
19
|
+
DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# acquia-cloud
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/Equiem/acquia-cloud)
|
|
4
|
+
[](https://gemnasium.com/Equiem/acquia-cloud)
|
|
5
|
+
|
|
6
|
+
**Source:** [https://github.com/Equiem/acquia-cloud](https://github.com/Equiem/acquia-cloud)
|
|
7
|
+
**Author:** [Equiem](http://equiem.com.au/)
|
|
8
|
+
**Contributors:** [See contributors on GitHub][gh-contrib]
|
|
9
|
+
**Bugs/Support:** [Github Issues][gh-issues]
|
|
10
|
+
**Copyright:** 2015
|
|
11
|
+
**License:** [MIT license][license]
|
|
12
|
+
**Status:** Active
|
|
13
|
+
|
|
14
|
+
## Synopsis
|
|
15
|
+
|
|
16
|
+
`acquia-cloud` is a Ruby binding for the Acquia Cloud API.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
$ gem install acquia-cloud
|
|
21
|
+
|
|
22
|
+
Or add `gem 'acquia-cloud'` to your Gemfile and update your bundle.
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
> TODO: Write this.
|
|
27
|
+
|
|
28
|
+
See also [the Cloud API documentation](https://cloudapi.acquia.com/).
|
|
29
|
+
|
|
30
|
+
[gh-contrib]: https://github.com/Equiem/acquia-cloud/graphs/contributors
|
|
31
|
+
[gh-issues]: https://github.com/Equiem/acquia-cloud/issues
|
|
32
|
+
[license]: https://github.com/Equiem/acquia-cloud/blob/master/LICENSE
|
data/Rakefile
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
$:.push File.join(__FILE__, '../lib')
|
|
2
|
+
require 'acquia/cloud/version'
|
|
3
|
+
|
|
4
|
+
def current_gems
|
|
5
|
+
Dir["pkg/acquia-cloud-#{Acquia::Cloud::VERSION}.gem"]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
namespace :gem do
|
|
9
|
+
desc 'Build gem'
|
|
10
|
+
task :build => [:clean] do
|
|
11
|
+
mkdir 'pkg' unless File.exist? 'pkg'
|
|
12
|
+
sh *%w{gem build acquia-cloud.gemspec}
|
|
13
|
+
Dir['*.gem'].each do |gem|
|
|
14
|
+
mv gem, "pkg/#{gem}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc 'Install gem'
|
|
19
|
+
task :install => ['gem:build'] do
|
|
20
|
+
sh *%W{gem install pkg/usmu-#{Acquia::Cloud::VERSION}.gem}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc 'Deploy gems to rubygems'
|
|
24
|
+
task :deploy => ['gem:build'] do
|
|
25
|
+
current_gems.each do |gem|
|
|
26
|
+
sh *%W{gem push #{gem}}
|
|
27
|
+
end
|
|
28
|
+
if File.exist? '.git'
|
|
29
|
+
sh *%W{git tag #{Acquia::Cloud::VERSION}}
|
|
30
|
+
sh *%W{git push origin tag #{Acquia::Cloud::VERSION}}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
task :clean
|
|
36
|
+
|
|
37
|
+
desc 'Run CI tasks.'
|
|
38
|
+
task :ci => [:rspec]
|
|
39
|
+
|
|
40
|
+
desc 'Run all RSpec tests.'
|
|
41
|
+
task :rspec do
|
|
42
|
+
sh 'bundle', 'exec', 'rspec'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc 'Run mutation tests'
|
|
46
|
+
task :mutant, [:target] do |t,args|
|
|
47
|
+
sh 'bundle', 'exec', 'mutant',
|
|
48
|
+
'--include', 'lib',
|
|
49
|
+
'--require', 'acquia/cloud',
|
|
50
|
+
'--use', 'rspec',
|
|
51
|
+
# Interfaces and documentation classes
|
|
52
|
+
# '--ignore-subject', 'Usmu::Deployment::RemoteFileInterface*',
|
|
53
|
+
args[:target] || 'Acquia::Cloud*'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
desc 'Run a console with our gems available'
|
|
57
|
+
task :console do
|
|
58
|
+
sh 'bundle', 'exec', 'irb', '-r', 'acquia/cloud'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
namespace :git do
|
|
62
|
+
desc 'Cleanup (delete) all local branches that have already been merged into master (locally)'
|
|
63
|
+
task :cleanup do
|
|
64
|
+
`git branch --merged master`.lines.map(&:chomp).select {|i| i != ' master' && i[0,2] != '* ' }.each {|b| sh "git branch -d #{b.strip}" }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
$:.push File.join(__FILE__, '../lib')
|
|
4
|
+
require 'acquia/cloud/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'acquia-cloud'
|
|
8
|
+
spec.version = Acquia::Cloud::VERSION
|
|
9
|
+
spec.authors = ['Equiem']
|
|
10
|
+
spec.email = ['sysadmin@equiem.com.au']
|
|
11
|
+
spec.summary = %q{Bindings to the Acquia Cloud API.}
|
|
12
|
+
spec.description = ''
|
|
13
|
+
spec.homepage = 'https://github.com/Equiem/BOTS'
|
|
14
|
+
spec.licenses = ['MIT']
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^spec/})
|
|
19
|
+
spec.require_paths = ['lib']
|
|
20
|
+
|
|
21
|
+
spec.required_ruby_version = Gem::Requirement.new('~> 2.1')
|
|
22
|
+
|
|
23
|
+
spec.add_dependency 'faraday', '~> 0.9'
|
|
24
|
+
spec.add_dependency 'websocket', '~> 1.2'
|
|
25
|
+
|
|
26
|
+
# Dev stuff.
|
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
|
28
|
+
spec.add_development_dependency 'rspec', '~> 3.3'
|
|
29
|
+
spec.add_development_dependency 'mutant', '~> 0.8'
|
|
30
|
+
spec.add_development_dependency 'mutant-rspec', '~> 0.8'
|
|
31
|
+
end
|
data/lib/acquia/cloud.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Acquia
|
|
5
|
+
# @see https://cloudapi.acquia.com/
|
|
6
|
+
class Cloud
|
|
7
|
+
attr_reader :api
|
|
8
|
+
|
|
9
|
+
def initialize(args = {})
|
|
10
|
+
@api = Api.new args
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def sites
|
|
14
|
+
@sites ||= @api.get('/sites').map do |site|
|
|
15
|
+
Site.new(self, site)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Acquia::Cloud::Site]
|
|
20
|
+
def site(name)
|
|
21
|
+
Site.new(self, name).refresh
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def drushrc
|
|
25
|
+
@api.get '/me/drushrc'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
%w{
|
|
31
|
+
version
|
|
32
|
+
errors
|
|
33
|
+
api
|
|
34
|
+
database
|
|
35
|
+
environment
|
|
36
|
+
server
|
|
37
|
+
site
|
|
38
|
+
task
|
|
39
|
+
logs/source
|
|
40
|
+
logs/streamer
|
|
41
|
+
}.each {|p| require "acquia/cloud/#{p}" }
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
module Acquia
|
|
3
|
+
class Cloud
|
|
4
|
+
class Api
|
|
5
|
+
API_VERSION = 'v1'
|
|
6
|
+
BASE_URL = 'https://cloudapi.acquia.com'
|
|
7
|
+
|
|
8
|
+
def initialize(args = {})
|
|
9
|
+
@acquia = Faraday.new(:url => 'https://cloudapi.acquia.com') do |client|
|
|
10
|
+
client.request :url_encoded
|
|
11
|
+
client.adapter Faraday.default_adapter
|
|
12
|
+
|
|
13
|
+
# Log request and response to STDOUT.
|
|
14
|
+
# client.use Faraday::Response::Logger
|
|
15
|
+
|
|
16
|
+
# Raise errors on HTTP error codes.
|
|
17
|
+
client.use Faraday::Response::RaiseError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
if args[:credentials].nil?
|
|
21
|
+
if ENV['ACQUIA_CLOUD_CREDENTIALS'].nil?
|
|
22
|
+
raise 'Unable to detect your credentials. Please populate ACQUIA_CLOUD_CREDENTIALS with your username and API key.'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
args[:credentials] = ENV['ACQUIA_CLOUD_CREDENTIALS']
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
credentials = args[:credentials].split(':', 2)
|
|
29
|
+
if credentials.length < 2
|
|
30
|
+
raise 'You must specify both username and API key in credentials.'
|
|
31
|
+
end
|
|
32
|
+
@acquia.basic_auth *credentials
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def get(url = nil, params = nil, headers = nil, &block)
|
|
36
|
+
request :get, url, params, headers, &block
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def post(url = nil, body = nil, headers = nil, &block)
|
|
41
|
+
request :post, url, body.nil? ? body : body.to_json, headers, &block
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def delete(url = nil, params = nil, headers = nil, &block)
|
|
45
|
+
request :delete, url, params, headers, &block
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
protected
|
|
49
|
+
|
|
50
|
+
def request(method, url = nil, arg2 = nil, headers = nil, &block)
|
|
51
|
+
response = @acquia.method(method).call "/#{API_VERSION}#{url}.json", arg2, headers, &block
|
|
52
|
+
JSON.load(response.body)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'acquia/cloud/entity'
|
|
2
|
+
|
|
3
|
+
module Acquia
|
|
4
|
+
class Cloud
|
|
5
|
+
class Database < Entity
|
|
6
|
+
def initialize(cloud, site, database)
|
|
7
|
+
@cloud = cloud
|
|
8
|
+
@site = site
|
|
9
|
+
@data = database
|
|
10
|
+
@url = "/sites/#{@site}/dbs/#{@data['name']}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def name
|
|
14
|
+
data['name']
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def backup_on(environment)
|
|
18
|
+
@cloud.site(@site).environment(environment).backup_database(name)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'acquia/cloud/entity'
|
|
2
|
+
|
|
3
|
+
module Acquia
|
|
4
|
+
class Cloud
|
|
5
|
+
class Environment < Entity
|
|
6
|
+
def initialize(cloud, site, environment)
|
|
7
|
+
@cloud = cloud
|
|
8
|
+
@site = site
|
|
9
|
+
@data = environment
|
|
10
|
+
@url = "/sites/#{@site}/envs/#{@data['name']}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def name
|
|
14
|
+
data['name']
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def vcs_path
|
|
18
|
+
data['vcs_path']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ssh_host
|
|
22
|
+
data['ssh_host']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def db_clusters
|
|
26
|
+
data['db_clusters']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def default_domain
|
|
30
|
+
data['default_domain']
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def unix_username
|
|
34
|
+
data['unix_username']
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# new_vcs_path should start with 'tags/' or 'heads/' to distinguish
|
|
38
|
+
# between tags or branches.
|
|
39
|
+
def deploy_path(new_vcs_path)
|
|
40
|
+
task = @cloud.api.post("#{@url}/code-deploy") do |response|
|
|
41
|
+
response.params['path'] = new_vcs_path
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
Task.new(@cloud, @site, task)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def backup_database(database_name)
|
|
48
|
+
task = @cloud.api.post("#{@url}/dbs/#{database_name}/backups")
|
|
49
|
+
Task.new @cloud, @site, task
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def logstream
|
|
53
|
+
response = @cloud.api.get("#{@url}/logstream")
|
|
54
|
+
Logs::Streamer.new(response['url'], JSON.parse(response['msg']))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def servers
|
|
58
|
+
@cloud.api.get("#{url}/servers").map do |server|
|
|
59
|
+
Server.new(@cloud, @site, name, server)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def server(server)
|
|
64
|
+
Server.new(@cloud, @site, name, {'name' => server}).refresh
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def database_servers
|
|
68
|
+
servers.select &:database?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def varnish_servers
|
|
72
|
+
servers.select &:varnish?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def web_servers
|
|
76
|
+
servers.select &:web?
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Acquia
|
|
2
|
+
class Cloud
|
|
3
|
+
module Logs
|
|
4
|
+
class Source
|
|
5
|
+
attr_reader :server
|
|
6
|
+
attr_reader :type
|
|
7
|
+
attr_reader :display_type
|
|
8
|
+
|
|
9
|
+
def initialize(server, type, display_type)
|
|
10
|
+
@server = server
|
|
11
|
+
@type = type
|
|
12
|
+
@display_type = display_type
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'websocket'
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'uri'
|
|
5
|
+
|
|
6
|
+
module Acquia
|
|
7
|
+
class Cloud
|
|
8
|
+
module Logs
|
|
9
|
+
# https://github.com/acquia/logstream/blob/master/README.md
|
|
10
|
+
class Streamer
|
|
11
|
+
# Try to retrieve 16KB blocks from the socket.
|
|
12
|
+
RECV_LENGTH = 16 * 1024
|
|
13
|
+
|
|
14
|
+
attr_reader :remote_server
|
|
15
|
+
|
|
16
|
+
def initialize(url, message)
|
|
17
|
+
@url = url
|
|
18
|
+
@message = message
|
|
19
|
+
@logs = []
|
|
20
|
+
@available = []
|
|
21
|
+
@enabled_types = []
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def debug
|
|
25
|
+
@debug = true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def connect
|
|
29
|
+
raise StreamerConnectionError, 'Already connected.' unless @socket.nil?
|
|
30
|
+
|
|
31
|
+
@handshake = ::WebSocket::Handshake::Client.new url: @url
|
|
32
|
+
uri = ::URI.parse @url
|
|
33
|
+
@socket = TCPSocket.new uri.host, uri.port || 80
|
|
34
|
+
@socket.print @handshake.to_s
|
|
35
|
+
|
|
36
|
+
until @handshake.finished?
|
|
37
|
+
@handshake << @socket.gets
|
|
38
|
+
end
|
|
39
|
+
raise StreamerConnectionError, "Couldn't get a valid response while connecting to the remote server: #{@url}" unless @handshake.valid?
|
|
40
|
+
@incoming = WebSocket::Frame::Incoming::Client.new(version: @handshake.version)
|
|
41
|
+
|
|
42
|
+
# Initial authentication
|
|
43
|
+
send @message
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def close
|
|
47
|
+
@socket.close
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def sources
|
|
51
|
+
update
|
|
52
|
+
@available.clone
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def enable(opts = {})
|
|
56
|
+
if opts[:source]
|
|
57
|
+
opts[:server] = opts[:source].server
|
|
58
|
+
opts[:type] = opts[:source].type
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
send({
|
|
62
|
+
cmd: 'enable',
|
|
63
|
+
server: opts[:server],
|
|
64
|
+
type: opts[:type],
|
|
65
|
+
})
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def enable_type(type)
|
|
69
|
+
@available.each do |source|
|
|
70
|
+
enable source: source
|
|
71
|
+
end
|
|
72
|
+
@enabled_types << type
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def disable(opts = {})
|
|
76
|
+
if opts[:source]
|
|
77
|
+
opts[:server] = opts[:source].server
|
|
78
|
+
opts[:type] = opts[:source].type
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
send({
|
|
82
|
+
cmd: 'disable',
|
|
83
|
+
server: opts[:server],
|
|
84
|
+
type: opts[:type],
|
|
85
|
+
})
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def disable_type(type)
|
|
89
|
+
@available.each do |source|
|
|
90
|
+
disable source: source
|
|
91
|
+
end
|
|
92
|
+
@enabled_types.delete type
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def each_log
|
|
96
|
+
update
|
|
97
|
+
until @logs.empty?
|
|
98
|
+
yield @logs.shift
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
protected
|
|
103
|
+
|
|
104
|
+
def send(message)
|
|
105
|
+
message = message.to_json
|
|
106
|
+
STDERR.puts "-> #{message}" if @debug
|
|
107
|
+
frame = ::WebSocket::Frame::Outgoing::Client.new(version: @handshake.version, type: 'text', data: message)
|
|
108
|
+
@socket.print frame.to_s
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def update
|
|
112
|
+
# Read as much as possible
|
|
113
|
+
@incoming << @socket.read_nonblock(RECV_LENGTH) while true
|
|
114
|
+
rescue ::IO::WaitReadable
|
|
115
|
+
loop do
|
|
116
|
+
msg = @incoming.next
|
|
117
|
+
break unless msg
|
|
118
|
+
STDERR.puts "<- #{msg}" if @debug
|
|
119
|
+
|
|
120
|
+
msg = JSON.parse(msg.data)
|
|
121
|
+
case msg['cmd']
|
|
122
|
+
when 'connected'
|
|
123
|
+
@remote_server = msg['server'] if msg['server'].start_with? 'logstream-api'
|
|
124
|
+
when 'success'
|
|
125
|
+
# Congratulations!
|
|
126
|
+
when 'error'
|
|
127
|
+
raise StreamerRemoteError, "#{msg['code']}: #{msg['description']} during #{msg['during'].inspect}"
|
|
128
|
+
when 'available'
|
|
129
|
+
source = Source.new(msg['server'], msg['type'], msg['display_type'])
|
|
130
|
+
@available << source
|
|
131
|
+
enable source: source if @enabled_types.include? source.type
|
|
132
|
+
when 'line'
|
|
133
|
+
@logs << msg
|
|
134
|
+
else
|
|
135
|
+
if @debug
|
|
136
|
+
STDERR.puts "Received unknown command: #{msg['cmd']}"
|
|
137
|
+
STDERR.puts msg.inspect
|
|
138
|
+
else
|
|
139
|
+
raise StreamerUnrecognisedCommandError, "Unrecognised command: #{msg['cmd']}\n#{msg.inspect}"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'acquia/cloud/entity'
|
|
2
|
+
|
|
3
|
+
module Acquia
|
|
4
|
+
class Cloud
|
|
5
|
+
class Server < Entity
|
|
6
|
+
def initialize(cloud, site, env, server)
|
|
7
|
+
@cloud = cloud
|
|
8
|
+
@site = site
|
|
9
|
+
@env = env
|
|
10
|
+
@data = server
|
|
11
|
+
@url = "/sites/#{@site}/envs/#{env}/servers/#{@data['name']}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def name
|
|
15
|
+
data['name']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def fqdn
|
|
19
|
+
data['fqdn']
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def ami_type
|
|
23
|
+
data['ami_type']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ec2_region
|
|
27
|
+
data['ec2_region']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def ec2_availability_zone
|
|
31
|
+
data['ec2_availability_zone']
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def services
|
|
35
|
+
data['services']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def varnish?
|
|
39
|
+
services.has_key? 'varnish'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def web?
|
|
43
|
+
services.has_key? 'web'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def database?
|
|
47
|
+
services.has_key? 'database'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def php_procs(memory_limit, apc_shm)
|
|
51
|
+
return nil unless web?
|
|
52
|
+
|
|
53
|
+
values = @cloud.api.get("#{url}/php-procs") do |response|
|
|
54
|
+
response.params['memory_limits[]'] = memory_limit
|
|
55
|
+
response.params['apc_shm[]'] = apc_shm
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
values['memory_limit'][memory_limit]['apc_shm'][apc_shm]['php_procs']
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'acquia/cloud/entity'
|
|
2
|
+
|
|
3
|
+
module Acquia
|
|
4
|
+
class Cloud
|
|
5
|
+
class Site < Entity
|
|
6
|
+
attr_reader :name
|
|
7
|
+
|
|
8
|
+
def initialize(cloud, name)
|
|
9
|
+
@cloud = cloud
|
|
10
|
+
@name = name
|
|
11
|
+
@url = "/sites/#{name}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def name
|
|
15
|
+
data['name']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def vcs_type
|
|
19
|
+
data['vcs_type'].to_sym
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def vcs_url
|
|
23
|
+
data['vcs_url']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def production_mode
|
|
27
|
+
data['production_mode'].to_i != 0
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def unix_username
|
|
31
|
+
data['unix_username']
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def title
|
|
35
|
+
data['title']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def uuid
|
|
39
|
+
data['uuid']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def environments
|
|
43
|
+
@cloud.api.get("#{@url}/envs").map do |environment|
|
|
44
|
+
Environment.new(@cloud, @name, environment)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def environment(name)
|
|
49
|
+
Environment.new(@cloud, @name, {'name' => name}).refresh
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def databases
|
|
53
|
+
@cloud.api.get("#{@url}/dbs").map do |db|
|
|
54
|
+
Database.new(@cloud, @name, db)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def database(name)
|
|
59
|
+
Database.new(@cloud, @name, {'name' => name}).refresh
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def tasks
|
|
63
|
+
@cloud.api.get("#{@url}/tasks").map do |task|
|
|
64
|
+
Task.new(@cloud, @name, task)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def task(id)
|
|
69
|
+
Task.new(@cloud, @name, {'id' => id}).refresh
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'acquia/cloud/entity'
|
|
2
|
+
|
|
3
|
+
module Acquia
|
|
4
|
+
class Cloud
|
|
5
|
+
class Task < Entity
|
|
6
|
+
def initialize(cloud, site, task)
|
|
7
|
+
@cloud = cloud
|
|
8
|
+
@site = site
|
|
9
|
+
@data = task
|
|
10
|
+
@url = "/sites/#{@site}/tasks/#{@data['id']}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def id
|
|
14
|
+
data['id']
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def queue
|
|
18
|
+
data['queue']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def state
|
|
22
|
+
data['state'].to_sym
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def description
|
|
26
|
+
data['description']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def created
|
|
30
|
+
Time.at(data['created'].to_i)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def started
|
|
34
|
+
Time.at(data['started'].to_i)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def completed
|
|
38
|
+
Time.at(data['completed'].to_i)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def logs
|
|
42
|
+
data['logs']
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def wait_for_completion(message = nil)
|
|
46
|
+
print message if message
|
|
47
|
+
loop do
|
|
48
|
+
# This will take several minutes, don't spam Acquia too hard while waiting.
|
|
49
|
+
sleep 15
|
|
50
|
+
print '.' if message
|
|
51
|
+
refresh
|
|
52
|
+
unless [:started].include? state
|
|
53
|
+
puts if message
|
|
54
|
+
break
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: acquia-cloud
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Equiem
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-11-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.9'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.9'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: websocket
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.2'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.2'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '10.4'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '10.4'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.3'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.3'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: mutant
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0.8'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0.8'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: mutant-rspec
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0.8'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0.8'
|
|
97
|
+
description: ''
|
|
98
|
+
email:
|
|
99
|
+
- sysadmin@equiem.com.au
|
|
100
|
+
executables: []
|
|
101
|
+
extensions: []
|
|
102
|
+
extra_rdoc_files: []
|
|
103
|
+
files:
|
|
104
|
+
- ".gitignore"
|
|
105
|
+
- ".ruby-version"
|
|
106
|
+
- ".travis.yml"
|
|
107
|
+
- Gemfile
|
|
108
|
+
- Gemfile.lock
|
|
109
|
+
- LICENSE
|
|
110
|
+
- README.md
|
|
111
|
+
- Rakefile
|
|
112
|
+
- acquia-cloud.gemspec
|
|
113
|
+
- lib/acquia/cloud.rb
|
|
114
|
+
- lib/acquia/cloud/api.rb
|
|
115
|
+
- lib/acquia/cloud/database.rb
|
|
116
|
+
- lib/acquia/cloud/entity.rb
|
|
117
|
+
- lib/acquia/cloud/environment.rb
|
|
118
|
+
- lib/acquia/cloud/errors.rb
|
|
119
|
+
- lib/acquia/cloud/logs/source.rb
|
|
120
|
+
- lib/acquia/cloud/logs/streamer.rb
|
|
121
|
+
- lib/acquia/cloud/server.rb
|
|
122
|
+
- lib/acquia/cloud/site.rb
|
|
123
|
+
- lib/acquia/cloud/task.rb
|
|
124
|
+
- lib/acquia/cloud/version.rb
|
|
125
|
+
homepage: https://github.com/Equiem/BOTS
|
|
126
|
+
licenses:
|
|
127
|
+
- MIT
|
|
128
|
+
metadata: {}
|
|
129
|
+
post_install_message:
|
|
130
|
+
rdoc_options: []
|
|
131
|
+
require_paths:
|
|
132
|
+
- lib
|
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - "~>"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '2.1'
|
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
|
+
requirements:
|
|
140
|
+
- - ">="
|
|
141
|
+
- !ruby/object:Gem::Version
|
|
142
|
+
version: '0'
|
|
143
|
+
requirements: []
|
|
144
|
+
rubyforge_project:
|
|
145
|
+
rubygems_version: 2.4.6
|
|
146
|
+
signing_key:
|
|
147
|
+
specification_version: 4
|
|
148
|
+
summary: Bindings to the Acquia Cloud API.
|
|
149
|
+
test_files: []
|