cloudmonkey 1.0.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.
- data/lib/cm.rb +180 -0
- metadata +48 -0
data/lib/cm.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'open3'
|
4
|
+
|
5
|
+
module CloudMonkey
|
6
|
+
class CMClient
|
7
|
+
def initialize(params)
|
8
|
+
@host = params[:host] || 'localhost'
|
9
|
+
@port = params[:port] || 8080
|
10
|
+
@apikey = params[:apikey]
|
11
|
+
@secretkey = params[:secretkey]
|
12
|
+
@config = params[:config] || File.join("#{Dir.home}", ".cloudmonkey-cmrb")
|
13
|
+
@debug = params[:debug] || false
|
14
|
+
configure
|
15
|
+
end
|
16
|
+
|
17
|
+
# Set a cloudmonkey configuration option.
|
18
|
+
def set(key, value)
|
19
|
+
run_cmd("set #{key} #{value}", nil)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Configure the cloudmonkey client for use with the library.
|
23
|
+
def configure
|
24
|
+
set('host', "#{@host}")
|
25
|
+
set('port', "#{@port}")
|
26
|
+
set('apikey', "#{@apikey}")
|
27
|
+
set('secretkey', "#{@secretkey}")
|
28
|
+
set('display', 'json')
|
29
|
+
set('asyncblock', 'false')
|
30
|
+
set('color', 'false')
|
31
|
+
end
|
32
|
+
|
33
|
+
# Execute a command with cloudmonkey. The command can be
|
34
|
+
# multi-word, e.g. "list users". Params, if provided, must be a
|
35
|
+
# hash (e.g. :account => "admin"), or a string value (.e.g "help"
|
36
|
+
# as the command and "list users" as the parameter).
|
37
|
+
def execute(cmd, params = nil)
|
38
|
+
cmd.downcase!
|
39
|
+
run_cmd(cmd, params)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Catch missing methods to transform them into cloudmonkey
|
43
|
+
# commands. This allows magic translation of ruby into cloudmonkey
|
44
|
+
# commands. Because cloudmonkey api commands have a specific
|
45
|
+
# format of 1 or more words followed by key=value parameters, we
|
46
|
+
# turn the method_name into "method name" and pass in the first
|
47
|
+
# argument only, which is assumed to be a hash or SINGLE string
|
48
|
+
# value.
|
49
|
+
def method_missing(name, *args)
|
50
|
+
cmd = name.to_s.split('_').join(' ').strip
|
51
|
+
execute cmd, args[0]
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
# Run a cloudmonkey command.
|
56
|
+
def run_cmd(input, params = nil)
|
57
|
+
input += ' '
|
58
|
+
|
59
|
+
# We recognize hash parameters and straight-up string
|
60
|
+
# parameters, but nothing else
|
61
|
+
unless params.nil?
|
62
|
+
if params.is_a?(Hash)
|
63
|
+
params.each { |key, value| input += "#{key.downcase}=#{value} " }
|
64
|
+
input.chop!
|
65
|
+
elsif params.is_a?(String)
|
66
|
+
input += params
|
67
|
+
else
|
68
|
+
raise 'We do not know how to handle these parameters'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
cmd = "cloudmonkey -c #{@config} #{input}"
|
73
|
+
output = nil
|
74
|
+
|
75
|
+
puts "running #{cmd}" if @debug
|
76
|
+
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
77
|
+
output = stdout.read
|
78
|
+
end
|
79
|
+
|
80
|
+
# usually the output is json, but not if it is an error or just
|
81
|
+
# general messages.
|
82
|
+
begin
|
83
|
+
json = JSON.parse(output, :symbolize_names => true)
|
84
|
+
# is it an async job? these responses usually have the id of
|
85
|
+
# whatever you are making and the jobid (2 keys)
|
86
|
+
if json.has_key?(:jobid) and json.length <= 2
|
87
|
+
handle_async_job(json[:jobid])
|
88
|
+
else
|
89
|
+
# it is a query result.
|
90
|
+
return json
|
91
|
+
end
|
92
|
+
rescue JSON::ParserError
|
93
|
+
handle_non_json_output(output)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Handle an async job that was submitted. This is for anything
|
98
|
+
# that is not a query method. The function has already been
|
99
|
+
# submitted, but we do need a result.
|
100
|
+
def handle_async_job(jobid)
|
101
|
+
result = run_cmd('query asyncjobresult', :jobid => jobid)
|
102
|
+
# see cs documentation for job status codes - 0 means pending
|
103
|
+
while result[:jobstatus] == 0
|
104
|
+
sleep(3)
|
105
|
+
result = run_cmd('query asyncjobresult', :jobid => jobid)
|
106
|
+
end
|
107
|
+
|
108
|
+
# if there is a job result, we are interested only in
|
109
|
+
# that. otherwise just return the whole response because we
|
110
|
+
# don't really know what's in it.
|
111
|
+
result.has_key?(:jobresult) ? result[:jobresult] : result
|
112
|
+
end
|
113
|
+
|
114
|
+
# Handle non-json output. This happens when Cloudmonkey returns an
|
115
|
+
# error or if it's just a generic message. Errors are raised as a
|
116
|
+
# runtime exception, while generic message sare put into a hash
|
117
|
+
# with a :message property.
|
118
|
+
def handle_non_json_output(message)
|
119
|
+
# handle various error messages, otherwise simply return a hash
|
120
|
+
# with the message
|
121
|
+
if message.start_with?('[Errno') or message.start_with?('Unauthorized:')
|
122
|
+
raise message
|
123
|
+
else
|
124
|
+
# if the message is non-0 length after stripping, then it is a
|
125
|
+
# valid message. otherwise it is nothing (nil).
|
126
|
+
{ :message => message } if message.strip.length > 0
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end # end cmclient
|
130
|
+
|
131
|
+
# For functions that require execution of many commands, or for
|
132
|
+
# unwrapping lists that Cloudmonkey returns.
|
133
|
+
class CMHelper
|
134
|
+
# cm is a CMClient
|
135
|
+
def initialize(cm)
|
136
|
+
@cm = cm
|
137
|
+
end
|
138
|
+
|
139
|
+
# Return a single network by name.
|
140
|
+
def list_physical_network(name)
|
141
|
+
networks = @cm.list_physicalnetworks(:name => name)
|
142
|
+
unless networks.nil?
|
143
|
+
return networks[:physicalnetwork][0] if networks[:count] > 0
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Return a single zone by name.
|
148
|
+
def list_zone(name)
|
149
|
+
zones = @cm.list_zones(:name => name)
|
150
|
+
unless zones.nil?
|
151
|
+
return zones[:zone][0] if zones[:count] > 0
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Enable a custom virtual router-derived network service
|
156
|
+
# provider. The provider will provide everything a VirtualRouter
|
157
|
+
# provides, but using itself instead of the regular VirtualRouter.
|
158
|
+
def enable_custom_vrouter_provider(provider, iface_id, zone_id)
|
159
|
+
nsp = @cm.add_networkserviceprovider(:name => provider, :physicalnetworkid => iface_id)
|
160
|
+
nsp = nsp[:networkserviceprovider]
|
161
|
+
|
162
|
+
element = @cm.create_virtualrouterelement(:nspid => nsp[:id])[:virtualrouterelement]
|
163
|
+
@cm.configure_virtualrouterelement(:enabled => true, :id => element[:id])
|
164
|
+
new_nsp = @cm.update_networkserviceprovider(:state => 'Enabled', :id => nsp[:id])
|
165
|
+
return new_nsp[:networkserviceprovider]
|
166
|
+
end
|
167
|
+
|
168
|
+
# Delete a network service provider by name and physical network ID.
|
169
|
+
def delete_network_service_provider(name, iface_id)
|
170
|
+
nsps = @cm.list_networkserviceproviders(:name => name, :phsyicalnetworkid => iface_id)
|
171
|
+
if nsps[:count] > 0
|
172
|
+
nsp = nsps[:networkserviceprovider][0]
|
173
|
+
@cm.delete_networkserviceprovider(:id => nsp[:id])
|
174
|
+
else
|
175
|
+
return false
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudmonkey
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- GreenQloud
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-03-27 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A simple interface to the CloudMonkey console command, allowing it to
|
15
|
+
be used in Ruby scripts.
|
16
|
+
email:
|
17
|
+
- developers@greenqloud.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/cm.rb
|
23
|
+
homepage: http://www.greenqloud.com
|
24
|
+
licenses:
|
25
|
+
- Apache
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 1.8.23
|
45
|
+
signing_key:
|
46
|
+
specification_version: 3
|
47
|
+
summary: CloudMonkey-Ruby
|
48
|
+
test_files: []
|