cloudn-api 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f86deae77bda5227585715b67913482877da788e
4
+ data.tar.gz: d8e0e476786d624151fc3fb1e594994a3665e58f
5
+ SHA512:
6
+ metadata.gz: a4d027f6ecbefa5331eda50b8aa0343a2a9343c8679bca94ef98e9e320767caffdd187736b02170b14711c6455d93bdce623f43d937e95b9441e558e74a580a3
7
+ data.tar.gz: e427b31a12f1f4ab3cc22f9ab68b37b67b84eef70e323f8390f20bd5104663a4fd116f815b73c7c2c1cfb7b242944853a659ce88efe7ed28b35eb96e75b803d1
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ Gemfile.lock
6
+ InstalledFiles
7
+ coverage
8
+ doc/
9
+ lib/bundler/man
10
+ pkg
11
+ rdoc
12
+ spec/reports
13
+ test/tmp
14
+ test/version_tmp
15
+ tmp
16
+ *.bundle
17
+ *.so
18
+ *.o
19
+ *.a
20
+ mkmf.log
21
+ .idea
22
+ vendor/bundle
23
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cloudn-api/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cloudn-api"
8
+ spec.version = CloudnAPI::VERSION
9
+ spec.authors = [""]
10
+ spec.email = [""]
11
+ spec.summary = %q{Library for manipulate Cloudn API easily}
12
+ spec.description = %q{Library for manipulate Cloudn API easily}
13
+ spec.homepage = "https://github.com/nttcom/cloudn-api"
14
+ spec.license = "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{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in CloudnAPI.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2015 NTT Communications Corporation, http://www.ntt.com
2
+
3
+ (The MIT License)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,86 @@
1
+ # CloudnAPI
2
+
3
+ CloudnAPI is a library for manipulating Cloudn API easily.
4
+
5
+ This library is designed as external library so you can't use CloudAPI alone like `./cloudn-api`.
6
+ If you need an executable one, then check [Cloudn CLI](https://github.com/nttcom/cloudn-cli).
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'cloudn-api'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install cloudn-api
21
+
22
+ Install path option such as '--path vendor/bundle' is recommended in order to limit scope.
23
+
24
+
25
+ ## Usage
26
+
27
+ 2 steps are required:
28
+
29
+ #### STEP 1. Set up Cloudn configuration
30
+ You can choose one of methods to write down the configuration:
31
+
32
+ - a) Create JSON file(*) wherever you like, then specify it when you create instance as STEP 2.
33
+ - b) Create JSON file at ~/.cloudnapi/config, which is the default location Cloudn API gem will seek.
34
+ - c) Set 3 Environmental Variables : 'CLOUDN_API_KEY', 'CLOUDN_SECRET_KEY', 'CLOUDN_URL'. The values of them is same as JSON file as follows.
35
+
36
+ *JSON file :
37
+
38
+ ```
39
+ {
40
+ "url" : "CLOUDN API ENDPOINT",
41
+ "api_key" : "YOUR API KEY",
42
+ "secret_key" : "YOUR SECRET KEY",
43
+ "debug_level" : "info"
44
+ }
45
+ ```
46
+
47
+ The string of debug_level is based on Ruby [Logger](http://www.ruby-doc.org/stdlib-2.1.2/libdoc/logger/rdoc/Logger.html).
48
+
49
+ #### STEP 2. Create instance of Cloudn API (Synopsis)
50
+ Write down some fancy codes with Cloudn API.
51
+
52
+ ```
53
+ require 'cloudn-api'
54
+
55
+ # Create Cloudn API instance
56
+ client = CloudnAPI::Client.new
57
+
58
+ # Configuration file can be specified here explicitly.
59
+ ## client = CloudnAPI::Client.new('hoge/foobar.json')
60
+
61
+ # Then use Cloudn API
62
+
63
+ ## when an API doesn't need any options, call method with no argument like this:
64
+ client.listUsers
65
+
66
+ ## when an API needs options, then call method with arguments like this:
67
+ client.listUsers({ keyword: 'YOUR KEY WORD' })
68
+ ```
69
+
70
+ Methods available are checked at :
71
+
72
+ - http://www.cloudn-service.com/guide/manuals/html/flat-api/
73
+ - http://www.cloudn-service.com/guide/manuals/html/vpcopennw-api/
74
+
75
+
76
+ ## Misc
77
+
78
+ - Async query is handled as synced query, which means CloudnAPI library waits for http response from Cloudn.
79
+
80
+ ## Contributing
81
+
82
+ 1. Fork it ( https://github.com/[my-github-username]/CloudnAPI/fork )
83
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
84
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
85
+ 4. Push to the branch (`git push origin my-new-feature`)
86
+ 5. Create a new Pull Request
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -0,0 +1,3 @@
1
+ require 'cloudn-api/version'
2
+ require 'cloudn-api/client'
3
+
@@ -0,0 +1,345 @@
1
+ [
2
+ "activateProject",
3
+ "addAccountToProject",
4
+ "addCluster",
5
+ "addExternalFirewall",
6
+ "addExternalLoadBalancer",
7
+ "addF5LoadBalancer",
8
+ "addHost",
9
+ "addNetscalerLoadBalancer",
10
+ "addNetworkDevice",
11
+ "addNetworkServiceProvider",
12
+ "addNiciraNvpDevice",
13
+ "addNicToVirtualMachine",
14
+ "addS3",
15
+ "addSecondaryStorage",
16
+ "addSrxFirewall",
17
+ "addSwift",
18
+ "addTrafficMonitor",
19
+ "addTrafficType",
20
+ "addVpnUser",
21
+ "assignToLoadBalancerRule",
22
+ "assignVirtualMachine",
23
+ "associateIpAddress",
24
+ "associateLun",
25
+ "attachIso",
26
+ "attachVolume",
27
+ "authorizeSecurityGroupEgress",
28
+ "authorizeSecurityGroupIngress",
29
+ "cancelHostMaintenance",
30
+ "cancelStorageMaintenance",
31
+ "changeServiceForRouter",
32
+ "changeServiceForSystemVm",
33
+ "changeServiceForVirtualMachine",
34
+ "configureF5LoadBalancer",
35
+ "configureNetscalerLoadBalancer",
36
+ "configureSrxFirewall",
37
+ "configureVirtualRouterElement",
38
+ "copyIso",
39
+ "copyTemplate",
40
+ "createAccount",
41
+ "createAutoScalePolicy",
42
+ "createAutoScaleVmGroup",
43
+ "createAutoScaleVmProfile",
44
+ "createCondition",
45
+ "createCounter",
46
+ "createDiskOffering",
47
+ "createDomain",
48
+ "createFirewallRule",
49
+ "createInstanceGroup",
50
+ "createIpForwardingRule",
51
+ "createLBStickinessPolicy",
52
+ "createLoadBalancerRule",
53
+ "createLunOnFiler",
54
+ "createNetwork",
55
+ "createNetworkACL",
56
+ "createNetworkACLList",
57
+ "createNetworkOffering",
58
+ "createPhysicalNetwork",
59
+ "createPod",
60
+ "createPool",
61
+ "createPortForwardingRule",
62
+ "createPrivateGateway",
63
+ "createProject",
64
+ "createRemoteAccessVpn",
65
+ "createSSHKeyPair",
66
+ "createSecurityGroup",
67
+ "createServiceOffering",
68
+ "createSnapshot",
69
+ "createSnapshotPolicy",
70
+ "createStaticRoute",
71
+ "createStorageNetworkIpRange",
72
+ "createStoragePool",
73
+ "createTags",
74
+ "createTemplate",
75
+ "createUser",
76
+ "createVPC",
77
+ "createVPCOffering",
78
+ "createVirtualRouterElement",
79
+ "createVlanIpRange",
80
+ "createVolume",
81
+ "createVolumeOnFiler",
82
+ "createVpnConnection",
83
+ "createVpnCustomerGateway",
84
+ "createVpnGateway",
85
+ "createZone",
86
+ "deleteAccount",
87
+ "deleteAccountFromProject",
88
+ "deleteAutoScalePolicy",
89
+ "deleteAutoScaleVmGroup",
90
+ "deleteAutoScaleVmProfile",
91
+ "deleteCiscoNexusVSM",
92
+ "deleteCluster",
93
+ "deleteCondition",
94
+ "deleteCounter",
95
+ "deleteDiskOffering",
96
+ "deleteDomain",
97
+ "deleteExternalFirewall",
98
+ "deleteExternalLoadBalancer",
99
+ "deleteF5LoadBalancer",
100
+ "deleteFirewallRule",
101
+ "deleteHost",
102
+ "deleteInstanceGroup",
103
+ "deleteIpForwardingRule",
104
+ "deleteIso",
105
+ "deleteLBStickinessPolicy",
106
+ "deleteLoadBalancerRule",
107
+ "deleteNetscalerLoadBalancer",
108
+ "deleteNetwork",
109
+ "deleteNetworkACL",
110
+ "deleteNetworkDevice",
111
+ "deleteNetworkOffering",
112
+ "deleteNetworkServiceProvider",
113
+ "deleteNiciraNvpDevice",
114
+ "deletePhysicalNetwork",
115
+ "deletePod",
116
+ "deletePool",
117
+ "deletePortForwardingRule",
118
+ "deletePrivateGateway",
119
+ "deleteProject",
120
+ "deleteProjectInvitation",
121
+ "deleteRemoteAccessVpn",
122
+ "deleteSSHKeyPair",
123
+ "deleteSecurityGroup",
124
+ "deleteServiceOffering",
125
+ "deleteSnapshot",
126
+ "deleteSnapshotPolicies",
127
+ "deleteSrxFirewall",
128
+ "deleteStaticRoute",
129
+ "deleteStorageNetworkIpRange",
130
+ "deleteStoragePool",
131
+ "deleteTags",
132
+ "deleteTemplate",
133
+ "deleteTrafficMonitor",
134
+ "deleteTrafficType",
135
+ "deleteUser",
136
+ "deleteVPC",
137
+ "deleteVPCOffering",
138
+ "deleteVlanIpRange",
139
+ "deleteVolume",
140
+ "deleteVpnConnection",
141
+ "deleteVpnCustomerGateway",
142
+ "deleteVpnGateway",
143
+ "deleteZone",
144
+ "deployVirtualMachine",
145
+ "destroyLunOnFiler",
146
+ "destroyRouter",
147
+ "destroySystemVm",
148
+ "destroyVirtualMachine",
149
+ "destroyVolumeOnFiler",
150
+ "detachIso",
151
+ "detachVolume",
152
+ "disableAccount",
153
+ "disableAutoScaleVmGroup",
154
+ "disableCiscoNexusVSM",
155
+ "disableStaticNat",
156
+ "disableUser",
157
+ "disassociateIpAddress",
158
+ "dissociateLun",
159
+ "enableAccount",
160
+ "enableAutoScaleVmGroup",
161
+ "enableCiscoNexusVSM",
162
+ "enableStaticNat",
163
+ "enableStorageMaintenance",
164
+ "enableUser",
165
+ "extractIso",
166
+ "extractTemplate",
167
+ "extractVolume",
168
+ "generateUsageRecords",
169
+ "getApiLimit",
170
+ "getCloudIdentifier",
171
+ "getUser",
172
+ "getVMPassword",
173
+ "ldapConfig",
174
+ "ldapRemove",
175
+ "listAccounts",
176
+ "listAlerts",
177
+ "listApis",
178
+ "listAsyncJobs",
179
+ "listAutoScalePolicies",
180
+ "listAutoScaleVmGroups",
181
+ "listAutoScaleVmProfiles",
182
+ "listCapabilities",
183
+ "listCapacity",
184
+ "listCiscoNexusVSMs",
185
+ "listClusters",
186
+ "listConditions",
187
+ "listConfigurations",
188
+ "listCounters",
189
+ "listDiskOfferings",
190
+ "listDomainChildren",
191
+ "listDomains",
192
+ "listEventTypes",
193
+ "listEvents",
194
+ "listExternalFirewalls",
195
+ "listExternalLoadBalancers",
196
+ "listF5LoadBalancerNetworks",
197
+ "listF5LoadBalancers",
198
+ "listFirewallRules",
199
+ "listHosts",
200
+ "listHypervisorCapabilities",
201
+ "listHypervisors",
202
+ "listInstanceGroups",
203
+ "listIpForwardingRules",
204
+ "listIsoPermissions",
205
+ "listIsos",
206
+ "listLBStickinessPolicies",
207
+ "listLoadBalancerRuleInstances",
208
+ "listLoadBalancerRules",
209
+ "listLunsOnFiler",
210
+ "listNetscalerLoadBalancerNetworks",
211
+ "listNetscalerLoadBalancers",
212
+ "listNetworkACLs",
213
+ "listNetworkACLLists",
214
+ "listNetworkDevice",
215
+ "listNetworkOfferings",
216
+ "listNetworkServiceProviders",
217
+ "listNetworks",
218
+ "listNiciraNvpDeviceNetworks",
219
+ "listNiciraNvpDevices",
220
+ "listOsCategories",
221
+ "listOsTypes",
222
+ "listPhysicalNetworks",
223
+ "listPods",
224
+ "listPools",
225
+ "listPortForwardingRules",
226
+ "listPrivateGateways",
227
+ "listProjectAccounts",
228
+ "listProjectInvitations",
229
+ "listProjects",
230
+ "listPublicIpAddresses",
231
+ "listRemoteAccessVpns",
232
+ "listResourceLimits",
233
+ "listRouters",
234
+ "listS3s",
235
+ "listSSHKeyPairs",
236
+ "listSecurityGroups",
237
+ "listServiceOfferings",
238
+ "listSnapshotPolicies",
239
+ "listSnapshots",
240
+ "listSrxFirewallNetworks",
241
+ "listSrxFirewalls",
242
+ "listStaticRoutes",
243
+ "listStorageNetworkIpRange",
244
+ "listStoragePools",
245
+ "listSupportedNetworkServices",
246
+ "listSwifts",
247
+ "listSystemVms",
248
+ "listTags",
249
+ "listTemplatePermissions",
250
+ "listTemplates",
251
+ "listTrafficMonitors",
252
+ "listTrafficTypeImplementors",
253
+ "listTrafficTypes",
254
+ "listUsageRecords",
255
+ "listUsageTypes",
256
+ "listUsers",
257
+ "listVPCOfferings",
258
+ "listVPCs",
259
+ "listVirtualMachines",
260
+ "listVirtualRouterElements",
261
+ "listVlanIpRanges",
262
+ "listVolumes",
263
+ "listVolumesOnFiler",
264
+ "listVpnConnections",
265
+ "listVpnCustomerGateways",
266
+ "listVpnGateways",
267
+ "listVpnUsers",
268
+ "listZones",
269
+ "lockAccount",
270
+ "lockUser",
271
+ "markDefaultZoneForAccount",
272
+ "migrateSystemVm",
273
+ "migrateVirtualMachine",
274
+ "migrateVolume",
275
+ "modifyPool",
276
+ "prepareHostForMaintenance",
277
+ "prepareTemplate",
278
+ "queryAsyncJobResult",
279
+ "rebootRouter",
280
+ "rebootSystemVm",
281
+ "rebootVirtualMachine",
282
+ "reconnectHost",
283
+ "recoverVirtualMachine",
284
+ "registerIso",
285
+ "registerSSHKeyPair",
286
+ "registerTemplate",
287
+ "registerUserKeys",
288
+ "removeFromLoadBalancerRule",
289
+ "removeVpnUser",
290
+ "resetApiLimit",
291
+ "resetPasswordForVirtualMachine",
292
+ "resetVpnConnection",
293
+ "resizeVolume",
294
+ "restartNetwork",
295
+ "restartVPC",
296
+ "restoreVirtualMachine",
297
+ "revokeSecurityGroupEgress",
298
+ "revokeSecurityGroupIngress",
299
+ "startRouter",
300
+ "startSystemVm",
301
+ "startVirtualMachine",
302
+ "stopRouter",
303
+ "stopSystemVm",
304
+ "stopVirtualMachine",
305
+ "suspendProject",
306
+ "updateAccount",
307
+ "updateAutoScalePolicy",
308
+ "updateAutoScaleVmGroup",
309
+ "updateAutoScaleVmProfile",
310
+ "updateCluster",
311
+ "updateConfiguration",
312
+ "updateDiskOffering",
313
+ "updateDomain",
314
+ "updateHost",
315
+ "updateHostPassword",
316
+ "updateHypervisorCapabilities",
317
+ "updateInstanceGroup",
318
+ "updateIso",
319
+ "updateIsoPermissions",
320
+ "updateLoadBalancerRule",
321
+ "updateNetwork",
322
+ "updateNetworkOffering",
323
+ "updateNetworkServiceProvider",
324
+ "updatePhysicalNetwork",
325
+ "updatePod",
326
+ "updatePortForwardingRule",
327
+ "updateProject",
328
+ "updateProjectInvitation",
329
+ "updateResourceCount",
330
+ "updateResourceLimit",
331
+ "updateServiceOffering",
332
+ "updateStorageNetworkIpRange",
333
+ "updateStoragePool",
334
+ "updateTemplate",
335
+ "updateTemplatePermissions",
336
+ "updateTrafficType",
337
+ "updateUser",
338
+ "updateVPC",
339
+ "updateVPCOffering",
340
+ "updateVirtualMachine",
341
+ "updateVpnCustomerGateway",
342
+ "updateZone",
343
+ "uploadCustomCertificate",
344
+ "uploadVolume"
345
+ ]
@@ -0,0 +1,232 @@
1
+ module CloudnAPI
2
+
3
+ # In the Client class, there is camel-cased methods such as queryAsyncJobResult.
4
+ # Usually ruby methods are named along with snake-case,
5
+ # but this class needs to handle Cloudstack methods with Ruby's meta method : method_missing.
6
+ # So if you find camel-cased methods, you can think of that as calling Cloudstack method internally.
7
+
8
+ class Client
9
+
10
+ require 'json'
11
+ require 'openssl'
12
+ require 'open-uri'
13
+ require 'uri'
14
+ require 'base64'
15
+ require 'logger'
16
+ require 'erb'
17
+
18
+ API_LIST_PATH = '../api.json'
19
+ SLEEP_TIME_SEC = 5
20
+ RETRY_COUNT = 360 # wait for max 30 minutes
21
+ ASYNC_QUERY_FINISHED = 1
22
+ ASYNC_QUERY_ERROR = 2
23
+
24
+ attr_reader :api_key, :secret_key, :url, :api_list, :wait_async
25
+
26
+ def initialize(config_file = nil)
27
+ setup_logger_and_configs config_file
28
+
29
+ @api_key = @config_hash[:api_key].freeze
30
+ @secret_key = @config_hash[:secret_key].freeze
31
+ @url = URI.parse(@config_hash[:url]).freeze
32
+ @wait_async = true
33
+ end
34
+
35
+ # to handle CloudStack methods described in
36
+ # http://cloudstack.apache.org/docs/api/apidocs-4.0.0/TOC_User.html
37
+ # Note that I didn't test all methods,so some methods wouldn't work properly.
38
+ def method_missing(method, *args)
39
+ super unless @api_list.include? method.to_s
40
+ hash_response = args ? request_api(method, args.pop) : request_api(method)
41
+ @logger.info hash_response
42
+
43
+ if @wait_async and hash_response.values.pop.has_key? 'jobid'
44
+ result = wait_for_async_job(hash_response.values.pop.fetch('jobid'))
45
+ result = result['queryasyncjobresultresponse']
46
+ else
47
+ result = hash_response
48
+ end
49
+ @logger.debug(result)
50
+ result
51
+ end
52
+
53
+ def setup_logger_and_configs(config_file)
54
+ @logger = Logger.new(STDOUT)
55
+ load_config config_file
56
+ load_api_list
57
+ configure_logger
58
+ end
59
+
60
+ # Wait until async job is finished
61
+ def wait_for_async_job(jobid)
62
+ RETRY_COUNT.times {
63
+ result = queryAsyncJobResult(jobid)
64
+
65
+ # When async job has finished, let's escape from loop
66
+ if result['queryasyncjobresultresponse']['jobstatus'] == ASYNC_QUERY_FINISHED
67
+ # @logger.info result
68
+ break result
69
+ elsif result['queryasyncjobresultresponse']['jobstatus'] == ASYNC_QUERY_ERROR
70
+ @logger.error result
71
+ raise StandardError.new('Error occurred')
72
+ end
73
+ sleep SLEEP_TIME_SEC
74
+ }
75
+ end
76
+
77
+ # This method is only explicitly defined method for Cloudstack
78
+ # in order to prevent infinite loop of method_missing.
79
+ def queryAsyncJobResult(jobid)
80
+ @logger.info "Requesting :queryAsyncJobResult - jobid=#{jobid}"
81
+ request_api(:queryAsyncJobResult, {jobid: jobid})
82
+ end
83
+
84
+ # build query string, then issue http request to Cloudn end point
85
+ def request_api(method, args=nil)
86
+ if args
87
+ hash_cloudn_api = args.merge({ command: method.to_s })
88
+ query_str = build_query_str hash_cloudn_api
89
+ else
90
+ query_str = build_query_str({ command: method.to_s })
91
+ end
92
+ @logger.info "#{method} - #{@config_hash[:url]}?#{query_str}"
93
+ request query_str
94
+ end
95
+
96
+ # Set up logger instance
97
+ def configure_logger
98
+ @logger.progname = 'CloudnAPI'
99
+ @logger.datetime_format = "%Y-%m-%d %H:%M:%S "
100
+ log_level = @config_hash[:log_level] || :error
101
+ @logger.level =
102
+ case log_level.to_sym
103
+ when :info
104
+ Logger::INFO
105
+ when :debug
106
+ Logger::DEBUG
107
+ when :warn
108
+ Logger::WARN
109
+ when :error
110
+ Logger::ERROR
111
+ when :fatal
112
+ Logger::FATAL
113
+ else
114
+ Logger::INFO
115
+ end
116
+ end
117
+
118
+ # Issue HTTP request to API end point (url)
119
+ def request(query_string)
120
+ url = @url.dup
121
+ url.query = query_string
122
+
123
+ begin
124
+ response_text = OpenURI.open_uri(
125
+ url,
126
+ :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE,
127
+ 'User-Agent' => "CloudnAPI/#{RUBY_VERSION}"
128
+ ).read
129
+ rescue OpenURI::HTTPError => ex
130
+ @logger.error url
131
+ @logger.error ex
132
+ rescue Exception => ex
133
+ @logger.error url
134
+ @logger.error ex
135
+ end
136
+ parsed_reponse = JSON.parse(response_text)
137
+ end
138
+
139
+ # Build query string such as
140
+ # command=...&response=json&apiKey=...&signature=...
141
+ # @param hash_cloudn_api [Hash] hash of commands for cloudstack API
142
+ def build_query_str(hash_cloudn_api)
143
+ # Prepare to create signature and query string.
144
+ hash_cloudn_api_with_key = hash_cloudn_api.merge({:response => :json, :apikey => @api_key})
145
+
146
+ # Create signature
147
+ encoded_str = encode(hash_cloudn_api_with_key)
148
+ signature = create_signature encoded_str
149
+
150
+ # Create query string with signature
151
+ initial_str = hash_cloudn_api_with_key.flat_map {|k, v| "#{k}=#{ERB::Util.url_encode(v.to_s)}" }.join('&')
152
+ query_string = initial_str + "&signature=#{signature}"
153
+ end
154
+
155
+ # Create signature: Create HMAC with secret key, encode HMAC with Base64, and url-encode it
156
+ def create_signature(concatenated_str)
157
+ hmac = OpenSSL::HMAC::digest(::OpenSSL::Digest::SHA1.new, @secret_key, concatenated_str)
158
+ base64 = Base64.encode64(hmac).chomp
159
+ ERB::Util.url_encode(base64)
160
+ end
161
+
162
+ # Return url encoded string. Note: only values are url encoded.
163
+ def encode(param_hash)
164
+ encoded_hash = param_hash.each_with_object({}) { |(k, v), new_hash|
165
+ new_hash[k] = ERB::Util.url_encode(v.to_s).downcase
166
+ }
167
+ sorted_hash = Hash[encoded_hash.sort]
168
+ concatnated_str = sorted_hash.flat_map {|k, v| "#{k}=#{v}" }.join('&')
169
+ end
170
+
171
+ def load_api_list
172
+ api_list_path = File.expand_path(API_LIST_PATH, __FILE__)
173
+ list = open(api_list_path).read
174
+ @api_list = JSON.parse(list)
175
+ end
176
+
177
+ # Load configuration to @config_hash as follows
178
+ # 1. Check config_jfile which is explicitly specified
179
+ # 2. Check default location, ~/.cloudnapi/config
180
+ # 3. Check environmental variables
181
+ # If none of them can't be found, then report errors and exit.
182
+ def load_config(config_file)
183
+
184
+ # If config file is not specified, check default location
185
+ config_file = search_config_file unless config_file
186
+
187
+ # If there are ENV variables, then use them and return from this method.
188
+ # If none of them, configuration or Env variables, specified,
189
+ # then report error and exit.
190
+ unless config_file
191
+ if ENV['CLOUDN_API_KEY'] and ENV['CLOUDN_SECRET_KEY'] and ENV['CLOUDN_URL']
192
+ @config_hash = {}
193
+ @config_hash[:api_key] = ENV['CLOUDN_API_KEY']
194
+ @config_hash[:secret_key] = ENV['CLOUDN_SECRET_KEY']
195
+ @config_hash[:url] = ENV['CLOUDN_URL']
196
+ return
197
+ else
198
+ @logger.error("Couldn't find no configuration file.")
199
+ @logger.error('~/.cloudnapi/config or specify config file.')
200
+ exit 1
201
+ end
202
+ end
203
+
204
+ # Read and load @config_hash from config_file
205
+ config_body = open(config_file).read
206
+ begin
207
+ @config_hash = JSON.parse(config_body, {:symbolize_names => true})
208
+ rescue Exception => e
209
+ @logger.error("#{config_file} seems broken. Please check that ...")
210
+ @logger.error e
211
+ exit 1
212
+ end
213
+ end
214
+
215
+ # Find config file from HOME/.kneadn/config
216
+ # @return [String] path of config file
217
+ def search_config_file
218
+ default_config_path = ENV['HOME'] + '/.cloudnapi/config'
219
+ File.exists?(default_config_path) ? default_config_path : nil
220
+ end
221
+
222
+ end
223
+ end
224
+
225
+ # For Development and Debug
226
+ if __FILE__ == $0
227
+ require 'pp'
228
+
229
+ client = CloudnAPI::Client.new
230
+ result = client.listVPCs
231
+ pp result.to_json
232
+ end
@@ -0,0 +1,3 @@
1
+ module CloudnAPI
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ # These RSpec tests expect the configuration file of Cloudn to be in '~/.cloudnapi/config'.
4
+
5
+ describe CloudnAPI do
6
+ before do
7
+ @client = CloudnAPI::Client.new
8
+ end
9
+
10
+ it 'has a version number' do
11
+ expect(CloudnAPI::VERSION).not_to be nil
12
+ end
13
+
14
+ it 'has Cloudn configurations' do
15
+ expect(@client.api_key).to be
16
+ expect(@client.secret_key).to be
17
+ expect(@client.url).to be
18
+ expect(@client.api_list).to be
19
+ end
20
+
21
+ it 'can use Cloudn API' do
22
+ expect(@client.listUsers).to be
23
+ expect(@client.listUsers({ page: 1, pagesize: 1})).to be
24
+ end
25
+
26
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'cloudn-api'
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudn-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - ''
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Library for manipulate Cloudn API easily
56
+ email:
57
+ - ''
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - CloudnAPI.gemspec
65
+ - Gemfile
66
+ - LICENSE
67
+ - README.md
68
+ - Rakefile
69
+ - lib/cloudn-api.rb
70
+ - lib/cloudn-api/api.json
71
+ - lib/cloudn-api/client.rb
72
+ - lib/cloudn-api/version.rb
73
+ - spec/CloudnAPI_spec.rb
74
+ - spec/spec_helper.rb
75
+ homepage: https://github.com/nttcom/cloudn-api
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.2.2
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Library for manipulate Cloudn API easily
99
+ test_files:
100
+ - spec/CloudnAPI_spec.rb
101
+ - spec/spec_helper.rb