right_api_helper 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 +25 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +13 -0
- data/README.md +66 -0
- data/Rakefile +7 -0
- data/bin/organize +193 -0
- data/demo/deployments.json +44 -0
- data/demo/index.html +83 -0
- data/demo/logo.png +0 -0
- data/demo/start_server.sh +12 -0
- data/demo/tree.jquery.js +2947 -0
- data/lib/right_api_helper/api15.rb +357 -0
- data/lib/right_api_helper/base.rb +54 -0
- data/lib/right_api_helper/cache.rb +53 -0
- data/lib/right_api_helper/deployments.rb +39 -0
- data/lib/right_api_helper/instances.rb +46 -0
- data/lib/right_api_helper/scripts/deployments_creator.rb +44 -0
- data/lib/right_api_helper/session.rb +76 -0
- data/lib/right_api_helper/version.rb +3 -0
- data/lib/right_api_helper.rb +32 -0
- data/right_api_helper.gemspec +30 -0
- data/spec/api15_spec.rb +280 -0
- data/spec/cache_spec.rb +57 -0
- data/spec/data/deployments.json +44 -0
- data/spec/deployments_spec.rb +57 -0
- data/spec/instances_spec.rb +41 -0
- data/spec/scripts/deployments_creator_spec.rb +59 -0
- data/spec/session_spec.rb +46 -0
- data/spec/spec_helper.rb +50 -0
- metadata +214 -0
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
spec/cassettes/*
|
2
|
+
cache/*
|
3
|
+
.DS_Store
|
4
|
+
*.gem
|
5
|
+
*.rbc
|
6
|
+
.bundle
|
7
|
+
.config
|
8
|
+
.yardoc
|
9
|
+
Gemfile.lock
|
10
|
+
InstalledFiles
|
11
|
+
_yardoc
|
12
|
+
coverage
|
13
|
+
doc/
|
14
|
+
lib/bundler/man
|
15
|
+
pkg
|
16
|
+
rdoc
|
17
|
+
spec/reports
|
18
|
+
test/tmp
|
19
|
+
test/version_tmp
|
20
|
+
tmp
|
21
|
+
*.bundle
|
22
|
+
*.so
|
23
|
+
*.o
|
24
|
+
*.a
|
25
|
+
mkmf.log
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2014 RightScale, Inc.
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# RightApiHelper
|
2
|
+
|
3
|
+
A collection of helper objects and methods that encapsulate commonly used idioms for [right_api_client](https://github.com/rightscale/right_api_client) users.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'right_api_helper'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install right_api_helper
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
|
22
|
+
### Getting a connection
|
23
|
+
|
24
|
+
Get started by creating a [right_api_client](https://github.com/rightscale/right_api_client) handle:
|
25
|
+
|
26
|
+
@client = RightApiHelper::Session.new.create_client("someemail", "somepasswd", "someaccountid", "https://my.rightscale.com")
|
27
|
+
|
28
|
+
or
|
29
|
+
|
30
|
+
@client = RightApiHelper::Session.new.create_client_from_file("~/.right_api_client/login.yml")
|
31
|
+
|
32
|
+
### Using a helper
|
33
|
+
|
34
|
+
Now pass the client handle to a helper object to use it's methods:
|
35
|
+
|
36
|
+
deployment_helper = RightApiHelper::Deployments.new(@client)
|
37
|
+
my_deployment = @deployment_helper.find_or_create("My Cool Deployment")
|
38
|
+
|
39
|
+
### Logging
|
40
|
+
|
41
|
+
By default the helpers log to STDOUT. But you can modify that by passing a custom `Logger` to each helper. Here is the example from above modified to use a custom logger.
|
42
|
+
|
43
|
+
my_logger = Logger.new("/tmp/right_api.log)
|
44
|
+
deployment_helper = RightApiHelper::Deployments.new(client)
|
45
|
+
deployment_helper.logger(my_logger)
|
46
|
+
my_deployment = @deployment_helper.find_or_create("My Cool Deployment")
|
47
|
+
|
48
|
+
You can also pass a logger object to the `right_api_client` gem. For example:
|
49
|
+
|
50
|
+
session = RightApiHelper::Session.new
|
51
|
+
session.logger(my_logger)
|
52
|
+
@client = session.create_client_from_file("~/.right_api_client/login.yml")
|
53
|
+
|
54
|
+
|
55
|
+
## TODO
|
56
|
+
|
57
|
+
* Need to further sanitize VCR output before including spec/cassettes dir.
|
58
|
+
* break `lib/right_api_helper/api15.rb` apart into separate helpers?
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
1. Fork it ( https://github.com/caryp/right_api_helper/fork )
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
64
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
66
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/organize
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Author: cary@rightscale.com
|
4
|
+
# Copyright 2014 RightScale, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
# Example:
|
19
|
+
# bundle exec bin/organize preview demo/deployments.json --deployment-regexps="ec2:Name=([a-z]+)-([a-z])-([a-z]+)[0-9]+" --name-regexps="ec2:Name=[a-z]+-[a-z]-([a-z]+[0-9]+)"
|
20
|
+
#
|
21
|
+
# To better view results:
|
22
|
+
#
|
23
|
+
# > cd demo
|
24
|
+
# > ./start_server
|
25
|
+
#
|
26
|
+
# Then point your browser to http://localhost:8000/
|
27
|
+
#
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'thor'
|
31
|
+
require 'right_api_helper'
|
32
|
+
|
33
|
+
require 'pry'
|
34
|
+
|
35
|
+
class OrganizeApp < Thor
|
36
|
+
|
37
|
+
desc "preview FILE", "generate an organization preview and output to JSON file."
|
38
|
+
option :deployment_regexps, :required => true
|
39
|
+
option :prefix
|
40
|
+
option :name_regexps
|
41
|
+
option :debug, :type => :boolean
|
42
|
+
option :clear_cache, :type => :boolean
|
43
|
+
def preview(filename)
|
44
|
+
# setup
|
45
|
+
setup_logging(options[:debug])
|
46
|
+
initialize_api_client
|
47
|
+
setup_cache_objects(options[:clear_cache])
|
48
|
+
|
49
|
+
# organize
|
50
|
+
result_hash =
|
51
|
+
organize_by_tags(
|
52
|
+
get_tag_array(options[:deployment_regexps]),
|
53
|
+
get_tag_array(options[:name_regexps]),
|
54
|
+
options[:prefix]
|
55
|
+
)
|
56
|
+
|
57
|
+
# write results to a file
|
58
|
+
json = JSON.pretty_generate(result_hash)
|
59
|
+
@log.debug "JSON: #{json}"
|
60
|
+
File.open(filename, "w") { |f| f.write(json)}
|
61
|
+
@log.info("Done. Results written to '#{filename}'")
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def setup_logging(debug)
|
67
|
+
@log = Logger.new(STDOUT)
|
68
|
+
@log.formatter = proc do |severity, datetime, progname, msg|
|
69
|
+
"#{msg}\n"
|
70
|
+
end
|
71
|
+
@log.level = Logger::INFO
|
72
|
+
@log.level = Logger::DEBUG if debug
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize_api_client
|
76
|
+
session = RightApiHelper::Session.new
|
77
|
+
session.logger(@log)
|
78
|
+
@client ||= session.create_client_from_file("~/.right_api_client/login.yml")
|
79
|
+
end
|
80
|
+
|
81
|
+
def setup_cache_objects(clear=false)
|
82
|
+
@cache_dir = File.join(".", "cache")
|
83
|
+
@instance_cache ||= RightApiHelper::Cache.new("instances", @cache_dir)
|
84
|
+
@tag_cache ||= RightApiHelper::Cache.new("tags", @cache_dir)
|
85
|
+
if clear
|
86
|
+
@instance_cache.clear ; @tag_cache.clear
|
87
|
+
FileUtils.rmdir(@cache_dir)
|
88
|
+
end
|
89
|
+
FileUtils.mkdir(@cache_dir) unless File.directory?(@cache_dir)
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_tag_array(option)
|
93
|
+
array = []
|
94
|
+
array = option.split(",") if option
|
95
|
+
array
|
96
|
+
end
|
97
|
+
|
98
|
+
def instance_helper
|
99
|
+
@helper ||= RightApiHelper::Instances.new(@client)
|
100
|
+
@helper.logger(@log)
|
101
|
+
@helper
|
102
|
+
end
|
103
|
+
|
104
|
+
# organize into groups based on tags
|
105
|
+
#
|
106
|
+
# All instances who's captures match all deployment_regexps will be grouped
|
107
|
+
# together. The name of the group can be affected by passing in name_regexps and prefix.
|
108
|
+
#
|
109
|
+
# Array : deployment_regexps : list of namespace:key=value_regex values
|
110
|
+
#
|
111
|
+
# Returns: String : JSON object containing instances grouped by deployment_regexps
|
112
|
+
def organize_by_tags(deployment_regexps, name_regexps=[], prefix="")
|
113
|
+
@log.debug "ORGANIZE PARAMS: deployment_regexps: #{deployment_regexps} name_regexps: #{name_regexps}, prefix: #{prefix}"
|
114
|
+
output_hash = {}
|
115
|
+
|
116
|
+
# cached API queries for instances
|
117
|
+
instances_by_href = query_instances
|
118
|
+
|
119
|
+
# uncached tags query
|
120
|
+
instance_hrefs = instances_by_href.keys
|
121
|
+
@log.info "Querying tags from RightScale API..."
|
122
|
+
@log.debug "instance_hrefs: #{instance_hrefs.inspect}"
|
123
|
+
tag_data = @client.tags.by_resource(:resource_hrefs => instance_hrefs)
|
124
|
+
|
125
|
+
tag_data.each do |tag|
|
126
|
+
resources = tag.resource.is_a?(Array) ? tag.resource : [tag.resource]
|
127
|
+
resources.each do |resource|
|
128
|
+
tags = tag.tags.map{|t| t["name"]}
|
129
|
+
href = resource.href
|
130
|
+
relevant_tags_key= gather_relevant_tags(deployment_regexps, tags)
|
131
|
+
new_name = gather_relevant_tags(name_regexps, tags) if name_regexps
|
132
|
+
|
133
|
+
unless relevant_tags_key.empty?
|
134
|
+
instance_name = (new_name.nil? || new_name.empty?) ? instances_by_href[href] : new_name
|
135
|
+
instance_hash = {"href" => href, "type" => "Instance", "name" => instance_name}
|
136
|
+
output_hash[relevant_tags_key] ||= {"name" => "#{prefix}#{relevant_tags_key}", "children" => []}
|
137
|
+
output_hash[relevant_tags_key]["children"] << instance_hash
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
deployments_hash = { "deployments" => [] }
|
142
|
+
|
143
|
+
output_hash.each do |deployment_type, deployment_data|
|
144
|
+
deployments_hash["deployments"] << deployment_data
|
145
|
+
end
|
146
|
+
deployments_hash
|
147
|
+
end
|
148
|
+
|
149
|
+
# query instance data
|
150
|
+
#
|
151
|
+
# Use local cachefile to improve performance
|
152
|
+
#
|
153
|
+
def query_instances
|
154
|
+
instances_by_href = {}
|
155
|
+
if (instances_by_href = @instance_cache.get) == nil
|
156
|
+
@log.info "Querying instances from RightScale API (might take a few minutes)..."
|
157
|
+
instances = instance_helper.get_unmanaged_instances
|
158
|
+
instances_by_href = instances.inject({}) {|new_hash, instance| instance.show ; new_hash[instance.href] = existing_name(instance); new_hash}
|
159
|
+
@instance_cache.set(instances_by_href)
|
160
|
+
end
|
161
|
+
@log.debug "instances_by_href: #{instances_by_href.inspect}"
|
162
|
+
instances_by_href
|
163
|
+
end
|
164
|
+
|
165
|
+
def existing_name(instance)
|
166
|
+
if instance.respond_to?(:name)
|
167
|
+
instance.name
|
168
|
+
elsif instance.respond_to?(:resource_uid)
|
169
|
+
instance.resource_uid
|
170
|
+
else
|
171
|
+
"unknown"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def gather_relevant_tags(tag_regexps, tags, delimiter = '-')
|
176
|
+
return_tags = []
|
177
|
+
tag_regexps.each do |regexp_str|
|
178
|
+
regexp = Regexp.new(regexp_str)
|
179
|
+
match_data = nil
|
180
|
+
tags.detect{|t| match_data = regexp.match(t)}
|
181
|
+
return_tags += match_data.captures if match_data
|
182
|
+
end
|
183
|
+
return_tags.flatten.join(delimiter)
|
184
|
+
end
|
185
|
+
|
186
|
+
def client
|
187
|
+
@client ||= RightApi::Client.new(YAML.load_file(File.expand_path('~/.right_api_client/login.yml', __FILE__)))
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
params = OrganizeApp.start(ARGV)
|
193
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
{
|
2
|
+
"deployments": [
|
3
|
+
{
|
4
|
+
"name": "zensmartfeedpool-b-zookeeper",
|
5
|
+
"children": [
|
6
|
+
{
|
7
|
+
"href": "/api/clouds/3/instances/CFD3EJB1P9L5D",
|
8
|
+
"type": "Instance",
|
9
|
+
"name": "i-fb8d86a4"
|
10
|
+
}
|
11
|
+
]
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"name": "zensmartfeedpool-a-zookeeper",
|
15
|
+
"children": [
|
16
|
+
{
|
17
|
+
"href": "/api/clouds/3/instances/C40BA3BLJ77JF",
|
18
|
+
"type": "Instance",
|
19
|
+
"name": "i-858d86da"
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"href": "/api/clouds/3/instances/42S13K03IDSDV",
|
23
|
+
"type": "Instance",
|
24
|
+
"name": "i-808d86df"
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"href": "/api/clouds/3/instances/8BKCHD746OE69",
|
28
|
+
"type": "Instance",
|
29
|
+
"name": "i-b91912e6"
|
30
|
+
}
|
31
|
+
]
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"name": "zensmartfeedpool-a-zook",
|
35
|
+
"children": [
|
36
|
+
{
|
37
|
+
"href": "/api/clouds/3/instances/80J8V6NUU2TOM",
|
38
|
+
"type": "Instance",
|
39
|
+
"name": "i-d9050e86"
|
40
|
+
}
|
41
|
+
]
|
42
|
+
}
|
43
|
+
]
|
44
|
+
}
|
data/demo/index.html
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
<html>
|
2
|
+
<style>
|
3
|
+
|
4
|
+
body {
|
5
|
+
min-width: 600px;
|
6
|
+
margin:0;
|
7
|
+
padding:0;
|
8
|
+
font-family:'Lucida Grande','Lucida Sans Unicode','Lucida Sans',Verdana,lucida,sans-serif;
|
9
|
+
background:#FFF;
|
10
|
+
height:100%
|
11
|
+
}
|
12
|
+
|
13
|
+
.banner {
|
14
|
+
background:#235186;
|
15
|
+
padding: 10;
|
16
|
+
}
|
17
|
+
|
18
|
+
.logo {
|
19
|
+
padding: 3 20 10;
|
20
|
+
|
21
|
+
float: left;
|
22
|
+
height:30px;
|
23
|
+
}
|
24
|
+
|
25
|
+
.bucket_name {
|
26
|
+
padding: 0 20 10;
|
27
|
+
|
28
|
+
font-size: 19px;
|
29
|
+
color: #F5F0A9;
|
30
|
+
background:#235186;
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
.disclaimer {
|
35
|
+
background: #FFFFFF;
|
36
|
+
margin-left: auto;
|
37
|
+
margin-right: auto;
|
38
|
+
position: relative;
|
39
|
+
color: black;
|
40
|
+
border: 2px solid black;
|
41
|
+
font-weight: normal;
|
42
|
+
font-size: 14px;
|
43
|
+
padding: 2px 20px;
|
44
|
+
position: relative;
|
45
|
+
clear: both;
|
46
|
+
}
|
47
|
+
|
48
|
+
.jqtree_common, h1, h2, h3 {
|
49
|
+
color: #235186;
|
50
|
+
background:#F5F2A9;
|
51
|
+
padding: 3;
|
52
|
+
margin: 0;
|
53
|
+
text-indent: 10;
|
54
|
+
}
|
55
|
+
.jqtree-title {
|
56
|
+
font-size: 16px;
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
</style>
|
62
|
+
<head>
|
63
|
+
<title>jQuery test</title>
|
64
|
+
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
|
65
|
+
<script src="tree.jquery.js"></script>
|
66
|
+
|
67
|
+
<script type="text/javascript">
|
68
|
+
$(function() {
|
69
|
+
$.getJSON(
|
70
|
+
'deployments.json',
|
71
|
+
function(result) {
|
72
|
+
$('#tree1').tree({ data: result.deployments });
|
73
|
+
});
|
74
|
+
});
|
75
|
+
</script>
|
76
|
+
</head>
|
77
|
+
<div class='banner'>
|
78
|
+
<div class='logo'><img alt='Embedded Image' width='140' height='19' src='logo.png' /></div>
|
79
|
+
<div class='bucket_name'>Instance Organize Preview</div>
|
80
|
+
|
81
|
+
</div>
|
82
|
+
<div id="tree1" data-url="."></div>
|
83
|
+
</html>
|
data/demo/logo.png
ADDED
Binary file
|