secured_cloud_api_client 0.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 916195ff166c0e20fa129e31f298034f147678dc
4
+ data.tar.gz: 0897f1d09d6f64740314bd33dfb90a29d8495a6f
5
+ SHA512:
6
+ metadata.gz: a2d734f61a03dfcb7966accd27efa0a90ecafcfda80d87f6057d50ede2f7c613c457701ce27c39fec398227b8d3fee6c8658b95fd02bc113a962a3aea01af0a7
7
+ data.tar.gz: a337d3ae467d0e7362f044633b3c2aae233120b3c9dfb2add5698bee7ead8e2a2563daa5ffd31476c0b3d86b8b5d8776647c2ede88264d47a4af6f4bf90f84be
@@ -0,0 +1,151 @@
1
+ require 'net/http'
2
+ require 'openssl'
3
+ require 'base64'
4
+
5
+
6
+ ##
7
+ # Class HttpClient performs HTTP requests to the Secured Cloud API Server.
8
+ # Authentication is handled via the supplied application key and shared secret.
9
+ #
10
+ # @author:: Alan Vella
11
+ ##
12
+
13
+ class HttpClient
14
+
15
+
16
+ APP_CONTENT_TYPE = "application/vnd.securedcloud.v7.0+json"
17
+ AUTH_SCHEME = "SC "
18
+
19
+
20
+ #Sends an HTTP GET request and returns response.
21
+ def self.sendGETRequest(authInfo, url)
22
+
23
+ @applicationKey = authInfo.getApplicationKey()
24
+ @sharedSecret = authInfo.getSharedSecret()
25
+
26
+ @url = URI.parse(url)
27
+ req = Net::HTTP::Get.new(url)
28
+
29
+ #Populate header with required stuff.
30
+ req['Accept'] = APP_CONTENT_TYPE
31
+ req['Authorization'] = AUTH_SCHEME + createAuthorization("GET", url)
32
+
33
+ #Execute request.
34
+ res = Net::HTTP.start(@url.host, @url.port) {|http|http.request(req)} # Net::HTTPResponse object
35
+
36
+ #Return response.
37
+ return res
38
+ end
39
+
40
+
41
+ #Sends an HTTP POST request and returns response.
42
+ def self.sendPOSTRequest(authInfo, url, body)
43
+
44
+ @applicationKey = authInfo.getApplicationKey()
45
+ @sharedSecret = authInfo.getSharedSecret()
46
+
47
+ @url = URI.parse(url)
48
+ req = Net::HTTP::Post.new(url)
49
+ req.body = body
50
+
51
+ #Populate header with required stuff.
52
+ req['Accept'] = APP_CONTENT_TYPE
53
+ req['Content-Type'] = APP_CONTENT_TYPE
54
+ req['Authorization'] = AUTH_SCHEME + createAuthorization("POST", url)
55
+
56
+ #Execute request.
57
+ res = Net::HTTP.start(@url.host, @url.port) {|http|http.request(req)} # Net::HTTPResponse object
58
+
59
+ #Return response.
60
+ return res
61
+ end
62
+
63
+
64
+ #Sends an HTTP DELETE request and returns response.
65
+ def self.sendDELETERequest(authInfo, url, params = nil)
66
+
67
+ @applicationKey = authInfo.getApplicationKey()
68
+ @sharedSecret = authInfo.getSharedSecret()
69
+
70
+ #Add parameters if present
71
+ if (params != nil) then
72
+ url += "?"
73
+ params.each do |param|
74
+ url += param[0] + "=" + param[1] + "&"
75
+ end
76
+
77
+ #Remove last ampersand
78
+ url = url[0...-1]
79
+ end
80
+
81
+ @url = URI.parse(url)
82
+ req = Net::HTTP::Delete.new(@url)
83
+
84
+ #Populate header with required stuff.
85
+ req['Accept'] = APP_CONTENT_TYPE
86
+ req['Content-Type'] = APP_CONTENT_TYPE
87
+ req['Authorization'] = AUTH_SCHEME + createAuthorization("DELETE", url)
88
+
89
+ #Execute request.
90
+ res = Net::HTTP.start(@url.host, @url.port) {|http|http.request(req)} # Net::HTTPResponse object
91
+
92
+ #Return response.
93
+ return res
94
+
95
+ end
96
+
97
+
98
+ #Sends an HTTP PUT request and returns response.
99
+ def self.sendPUTRequest(authInfo, url, params = nil)
100
+
101
+ @applicationKey = authInfo.getApplicationKey()
102
+ @sharedSecret = authInfo.getSharedSecret()
103
+
104
+ #Add parameters if present
105
+ if (params != nil) then
106
+ url += "?"
107
+ params.each do |param|
108
+ url += param[0] + "=" + param[1] + "&"
109
+ end
110
+ #Remove last ampersand
111
+ url = url[0...-1]
112
+ end
113
+
114
+ @url = URI.parse(url)
115
+ req = Net::HTTP::Put.new(@url)
116
+
117
+ #Populate header with required stuff.
118
+ req['Accept'] = APP_CONTENT_TYPE
119
+ req['Content-Type'] = APP_CONTENT_TYPE
120
+ req['Authorization'] = AUTH_SCHEME + createAuthorization("PUT", url)
121
+
122
+ #Execute request.
123
+ res = Net::HTTP.start(@url.host, @url.port) {|http|http.request(req)} # Net::HTTPResponse object
124
+
125
+ #Return response.
126
+ return res
127
+
128
+ end
129
+
130
+
131
+ #Removes the servlet name from a given external API URL.
132
+ def self.removeServletName(url)
133
+ urlAsArray = url.split("/");
134
+ newURL = ""
135
+ for i in 4..(urlAsArray.size() - 1)
136
+ newURL += "/" + urlAsArray[i]
137
+ end
138
+ return newURL
139
+ end
140
+
141
+
142
+ #Creates authorization header for a given method and URL.
143
+ def self.createAuthorization(method, url)
144
+ stringToSign = method + " " + removeServletName(url) + " " + @applicationKey
145
+ hash = OpenSSL::HMAC.digest('sha256', @sharedSecret, stringToSign)
146
+ requestSignature = Base64.encode64(hash).gsub(/\s+/, ' ').strip
147
+ credentials = @applicationKey + ":" + requestSignature;
148
+ encodedCredentials = Base64.encode64(credentials).gsub(/\s+/, ' ').strip
149
+ return encodedCredentials
150
+ end
151
+ end
@@ -0,0 +1,34 @@
1
+
2
+ ##
3
+ # A mapping between a set of public IPs and a private IP.
4
+ #
5
+ # @author:: Alan Vella
6
+ ##
7
+
8
+ class IpMapping
9
+
10
+
11
+ def initialize(privateIp, publicIps)
12
+ @privateIp = privateIp
13
+ @publicIps = publicIps
14
+ end
15
+
16
+
17
+ def get_details()
18
+ s = ""
19
+ if (@publicIps == nil) then
20
+ s = " Public IPs [ - ] => "
21
+ else
22
+ s = " Public IPs [" + @publicIps.join(", ") + "] => "
23
+ end
24
+ s += " Private IP [" + @privateIp + "]"
25
+ return s
26
+ end
27
+
28
+
29
+ def get_public_ips()
30
+ return @publicIps
31
+ end
32
+
33
+
34
+ end
@@ -0,0 +1,51 @@
1
+
2
+ ##
3
+ # OS Templates for creating new virtual machines.
4
+ #
5
+ # @author:: Alan Vella
6
+ ##
7
+
8
+ class OsTemplate
9
+
10
+
11
+ def initialize(name, version, minimumStorageSpace, defaultAdministratorUsername, diskExpandable)
12
+ @name = name
13
+ @version = version
14
+ @minimumStorageSpace = minimumStorageSpace
15
+ @defaultAdministratorUsername = defaultAdministratorUsername
16
+ @diskExpandable = diskExpandable
17
+ end
18
+
19
+
20
+ def get_details()
21
+ details = "Name : #{@name}\n"
22
+ details += "Version : #{@version}\n"
23
+ details += "Minimum Storage Space in Gb: #{@minimumStorageSpace}\n"
24
+ details += "Default Admin Username : #{@defaultAdministratorUsername}\n"
25
+ details += "Disk Expandable : #{@diskExpandable}\n"
26
+ return details
27
+ end
28
+
29
+
30
+ def get_name
31
+ return @name
32
+ end
33
+
34
+ def get_version
35
+ return @version
36
+ end
37
+
38
+ def get_minimum_storage_space
39
+ return @minimumStorageSpace
40
+ end
41
+
42
+ def get_administrator_username
43
+ return @defaultAdministratorUsername
44
+ end
45
+
46
+ def get_disk_expandable
47
+ return @diskExpandable
48
+ end
49
+
50
+
51
+ end
@@ -0,0 +1,43 @@
1
+
2
+ ##
3
+ # Class SecuredCloudConnection stores the details of a connection to the Secured Cloud API.
4
+ # An object of this type is needed whenever making calls to the API.
5
+ #
6
+ # @author:: Alan Vella
7
+ ##
8
+
9
+ class SecuredCloudConnection
10
+
11
+ #The URL must be in the format "http://10.239.32.201:8080/cloud-external-api-rest"
12
+ def initialize(url, applicationKey, sharedSecret)
13
+
14
+ #validation
15
+ raise ArgumentError, 'SecuredCloudConnection URL needs to be initialized' unless url != nil
16
+ raise ArgumentError, 'SecuredCloudConnection URL needs to be a valid string' unless url.respond_to?(:to_str)
17
+ raise ArgumentError, 'SecuredCloudConnection applicationKey needs to be initialized' unless applicationKey != nil
18
+ raise ArgumentError, 'SecuredCloudConnection applicationKey needs to be a valid string' unless applicationKey.respond_to?(:to_str)
19
+ raise ArgumentError, 'SecuredCloudConnection sharedSecret needs to be initialized' unless sharedSecret != nil
20
+ raise ArgumentError, 'SecuredCloudConnection sharedSecret needs to be a valid string' unless sharedSecret.respond_to?(:to_str)
21
+
22
+ @url = url
23
+ @applicationKey = applicationKey
24
+ @sharedSecret = sharedSecret
25
+
26
+ end
27
+
28
+
29
+ def getUrl
30
+ return @url
31
+ end
32
+
33
+
34
+ def getApplicationKey
35
+ return @applicationKey
36
+ end
37
+
38
+
39
+ def getSharedSecret
40
+ return @sharedSecret
41
+ end
42
+
43
+ end
@@ -0,0 +1,62 @@
1
+
2
+ ##
3
+ # Status of asynchronous tasks in Secured Cloud.
4
+ #
5
+ # @author:: Alan Vella
6
+ ##
7
+
8
+ class TaskStatus
9
+
10
+
11
+ def initialize(percentageComplete, requestStateEnum, result, errorCode, errorMessage, latestTaskDescription, processDescription, createdTimestamp, lastUpdatedTimeStamp)
12
+ @percentageComplete = percentageComplete
13
+ @requestStateEnum = requestStateEnum
14
+ @result = result
15
+ @errorCode = errorCode
16
+ @errorMessage = errorMessage
17
+ @latestTaskDescription = latestTaskDescription
18
+ @processDescription = processDescription
19
+ @createdTimestamp = createdTimestamp
20
+ @lastUpdatedTimeStamp = lastUpdatedTimeStamp
21
+ end
22
+
23
+
24
+ def get_details()
25
+ details = "Percentage Complete : #{@percentageComplete}\n"
26
+ details += "Request State : #{@requestStateEnum}\n"
27
+ details += "Result : #{@result}\n"
28
+ details += "Error Code : #{@errorCode}\n"
29
+ details += "Error Message : #{@errorMessage}\n"
30
+ details += "Latest Task Description: #{@latestTaskDescription}\n"
31
+ details += "Process Description : #{@processDescription}\n"
32
+ details += "Created Timestamp : #{@createdTimestamp}\n"
33
+ details += "Last Updated Timestamp : #{@lastUpdatedTimeStamp}\n"
34
+ return details
35
+ end
36
+
37
+
38
+ def get_result
39
+ return (@result.nil?) ? nil : @result["resourceURL"]
40
+ end
41
+
42
+ def get_error_code
43
+ return @errorCode
44
+ end
45
+
46
+
47
+ def get_error_message
48
+ return @errorMessage
49
+ end
50
+
51
+
52
+ def get_percentage_completed
53
+ return @percentageComplete
54
+ end
55
+
56
+
57
+ def get_latest_task_description
58
+ return @latestTaskDescription
59
+ end
60
+
61
+
62
+ end
@@ -0,0 +1,87 @@
1
+
2
+ ##
3
+ # Virtual machines.
4
+ #
5
+ # @author:: Alan Vella
6
+ ##
7
+
8
+ class VirtualMachine
9
+
10
+
11
+ def initialize(name, description, storageGB, storageType, memoryMB, vCPUs, powerStatus, nodeResource, organizationResource,
12
+ operatingSystemTemplate, imageResource, disks, macAddress, deducedPrivateIps, ipMappings)
13
+ @name = name
14
+ @description = description
15
+ @storageGB = storageGB
16
+ @storageType = storageType
17
+ @memoryMB = memoryMB
18
+ @vCPUs = vCPUs
19
+ @powerStatus = powerStatus
20
+ @nodeResource = nodeResource
21
+ @organizationResource = organizationResource
22
+ @operatingSystemTemplate = operatingSystemTemplate
23
+ @imageResource = imageResource
24
+ @disks = disks
25
+ @macAddress = macAddress
26
+ @deducedPrivateIps = deducedPrivateIps
27
+ @ipMappings = ipMappings
28
+ end
29
+
30
+
31
+ def get_details()
32
+ details = "Name : #{@name}\n"
33
+ details += "Description : #{@description}\n"
34
+ details += "Storage (GB) : #{@storageGB}\n"
35
+ details += "Storage Type : #{@storageType}\n"
36
+ details += "Memory (Mb) : #{@memoryMB}\n"
37
+ details += "vCPUs : #{@vCPUs}\n"
38
+ details += "Power Status : #{@powerStatus}\n"
39
+ details += "Node Resource : #{@nodeResource}\n"
40
+ details += "Organization Resource : #{@organizationResource}\n"
41
+ details += "Operation System Template: #{@operatingSystemTemplate}\n"
42
+ details += "Image Resource : #{@imageResource}\n"
43
+ if (@disks == nil) then
44
+ details += "Disks : -\n"
45
+ else
46
+ details += "Disks : #{@disks.join(", ")}\n"
47
+ end
48
+ if (@deducedPrivateIps == nil) then
49
+ details += "Deduced Private IPs : -\n"
50
+ else
51
+ details += "Deduced Private IPs : #{@deducedPrivateIps.join(", ")}\n"
52
+ end
53
+ details += "IP Mappings:"
54
+ @ipMappings.each do |ipMapping|
55
+ details += "\n\t#{ipMapping.get_details()}"
56
+ end
57
+ details += "\nMAC Address : #{@macAddress}\n"
58
+ return details
59
+ end
60
+
61
+
62
+ def get_power_status
63
+ return @powerStatus
64
+ end
65
+
66
+
67
+ def get_os_template_resource_url
68
+ return @operatingSystemTemplate
69
+ end
70
+
71
+
72
+ def get_image_resource_url
73
+ return @imageResource
74
+ end
75
+
76
+
77
+ def get_ip_mappings
78
+ return @ipMappings
79
+ end
80
+
81
+
82
+ def get_name
83
+ return @name
84
+ end
85
+
86
+
87
+ end
@@ -0,0 +1,30 @@
1
+
2
+ ##
3
+ # A private IP of a virtual machine.
4
+ #
5
+ # @author:: Alan Vella
6
+ ##
7
+
8
+ class VmPrivateIp
9
+
10
+
11
+ def initialize(ipAddress, assignedTo, publicIpMappings, nodeResource, organizationResource)
12
+ @ipAddress = ipAddress
13
+ @assignedTo = assignedTo
14
+ @publicIpMappings = publicIpMappings
15
+ @nodeResource = nodeResource
16
+ @organizationResource = organizationResource
17
+ end
18
+
19
+
20
+ def get_details()
21
+ details = "IP Address : #{@ipAddress}\n"
22
+ details += "Assigned To : #{@assignedTo.join(", ")}\n"
23
+ details += "Public IP Mappings : #{@publicIpMappings.join(", ")}\n"
24
+ details += "Node Resource : #{@nodeResource}\n"
25
+ details += "Organization Resource: #{@organizationResource}\n"
26
+ return details
27
+ end
28
+
29
+
30
+ end
@@ -0,0 +1,34 @@
1
+
2
+ ##
3
+ # A public IP of a virtual machine.
4
+ #
5
+ # @author:: Alan Vella
6
+ ##
7
+
8
+ class VmPublicIp
9
+
10
+
11
+ def initialize(ipAddress, ipType, reserved, assignedTo, privateIpMapping, nodeResource, organizationResource)
12
+ @ipAddress = ipAddress
13
+ @ipType = ipType
14
+ @reserved = reserved
15
+ @assignedTo = assignedTo
16
+ @privateIpMapping = privateIpMapping
17
+ @nodeResource = nodeResource
18
+ @organizationResource = organizationResource
19
+ end
20
+
21
+
22
+ def get_details()
23
+ details = "IP Address : #{@ipAddress}\n"
24
+ details += "IP Type : #{@ipType}\n"
25
+ details += "Reserved : #{@reserved}\n"
26
+ details += "Assigned To : #{@assignedTo.join(", ")}\n"
27
+ details += "Private IP Mapping : #{@privateIpMapping}\n"
28
+ details += "Node Resource : #{@nodeResource}\n"
29
+ details += "Organization Resource: #{@organizationResource}\n"
30
+ return details
31
+ end
32
+
33
+
34
+ end
@@ -0,0 +1,534 @@
1
+ require "json"
2
+
3
+ require_relative "secured_cloud_api_client/http_client"
4
+ require_relative "secured_cloud_api_client/sc_connection"
5
+ require_relative "secured_cloud_api_client/os_template"
6
+ require_relative "secured_cloud_api_client/task_status"
7
+ require_relative "secured_cloud_api_client/virtual_machine"
8
+ require_relative "secured_cloud_api_client/ip_mapping"
9
+ require_relative "secured_cloud_api_client/vm_private_ip"
10
+ require_relative "secured_cloud_api_client/vm_public_ip"
11
+
12
+
13
+ ##
14
+ # Class SecuredCloudRestClient provides a collection of methods that
15
+ # issue requests to the Secured Cloud RESTful External API.
16
+ #
17
+ # @author:: Alan Vella, Secured Cloud
18
+ ##
19
+
20
+ class SecuredCloudRestClient
21
+
22
+
23
+ #validation for sc_connection objects used by all api calls
24
+ def self.validate_sc_connection(sc_connection)
25
+ raise ArgumentError, 'SecuredCloudConnection needs to be initialized' unless sc_connection != nil
26
+ raise ArgumentError, 'SecuredCloudConnection needs to implement getUrl()' unless sc_connection.respond_to?(:getUrl)
27
+ raise ArgumentError, 'SecuredCloudConnection needs to implement getApplicationKey()' unless sc_connection.respond_to?(:getApplicationKey)
28
+ raise ArgumentError, 'SecuredCloudConnection needs to implement getSharedSecret()' unless sc_connection.respond_to?(:getSharedSecret)
29
+ end
30
+ private_class_method :validate_sc_connection
31
+
32
+ #validation for resource URLs used by all api calls
33
+ def self.validate_resource(resourceName, resource)
34
+ raise ArgumentError, resourceName.to_s + ' needs to be initialized' unless resource != nil
35
+ raise ArgumentError, resourceName.to_s + ' needs to be a valid string' unless resource.respond_to?(:to_str)
36
+ end
37
+ private_class_method :validate_sc_connection
38
+
39
+
40
+ # Returns a list of available nodes for a given organization.
41
+ def self.getNodesAvailable(sc_connection, orgResource)
42
+
43
+ #validation
44
+ validate_sc_connection(sc_connection)
45
+ validate_resource("Organization Resource", orgResource)
46
+
47
+ response = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + orgResource + "/node" )
48
+ nodesAvailable = []
49
+ responseBodyAsObject = JSON.parse(response.body)
50
+ responseBodyAsObject.each do |item|
51
+ nodesAvailable.push(item["resourceURL"])
52
+ end
53
+
54
+ return nodesAvailable
55
+ end
56
+
57
+
58
+ # Returns a list of available OS templates for a given organization and node.
59
+ def self.getOsTemplatesAvailable(sc_connection, orgResource, nodeResource)
60
+
61
+ #validation
62
+ validate_sc_connection(sc_connection)
63
+ validate_resource("Organization Resource", orgResource)
64
+ validate_resource("Node Resource", nodeResource)
65
+
66
+ response = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + orgResource + nodeResource + "/ostemplate")
67
+ osTemplatesAvailable = []
68
+ responseBodyAsObject = JSON.parse(response.body)
69
+
70
+ responseBodyAsObject.each do |item|
71
+ osTemplatesAvailable.push(item["resourceURL"])
72
+ end
73
+
74
+ return osTemplatesAvailable
75
+ end
76
+
77
+
78
+ # Returns the details of an OS template
79
+ def self.getOsTemplateDetails(sc_connection, osTemplateResource)
80
+
81
+ #validation
82
+ validate_sc_connection(sc_connection)
83
+ validate_resource("OS Template", osTemplateResource)
84
+
85
+ osResponse = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + osTemplateResource )
86
+ responseBodyAsObject = JSON.parse(osResponse.body)
87
+ osName = osVersion = minimumStorageSpace = defaultAdministratorUsername = diskExpandable = ""
88
+
89
+ responseBodyAsObject.each do |item|
90
+ if item[0] == "name" then
91
+ osName = item[1]
92
+ elsif item[0] == "version" then
93
+ osVersion = item[1]
94
+ elsif item[0] == "minimumStorageSpace" then
95
+ minimumStorageSpace = item[1]
96
+ elsif item[0] == "defaultAdministratorUsername" then
97
+ defaultAdministratorUsername = item[1]
98
+ elsif item[0] == "diskExpandable" then
99
+ diskExpandable = item[1]
100
+ end
101
+ end
102
+
103
+ return OsTemplate.new(osName, osVersion, minimumStorageSpace, defaultAdministratorUsername, diskExpandable)
104
+ end
105
+
106
+
107
+ # Starts a Create VM transaction.
108
+ # Returns the response code as well as the task resource
109
+ # if the transaction is triggered successfully.
110
+ def self.createVM(sc_connection, orgResource, nodeResource, name, description, storageGB, memoryMB, vCPUCount, powerStatus, imageResource, osTemplateResource, osPassword)
111
+
112
+ #validation
113
+ validate_sc_connection(sc_connection)
114
+ validate_resource("Organization Resource", orgResource)
115
+ validate_resource("Node Resource", nodeResource)
116
+
117
+ createVMPostBody = createVMJSONBody(name, description, storageGB, memoryMB, vCPUCount, powerStatus, imageResource, osTemplateResource, osPassword)
118
+ response = HttpClient.sendPOSTRequest( sc_connection, sc_connection.getUrl() + orgResource + nodeResource + "/virtualmachine", createVMPostBody)
119
+
120
+ if (response.code == "202") then
121
+ responseBodyAsObject = JSON.parse(response.body)
122
+ responseBodyAsObject.each do |item|
123
+ return "202", item[1]
124
+ end
125
+ else
126
+ return response.code, response['X-Application-Error-Reference'], response['X-Application-Error-Description']
127
+ end
128
+
129
+ end
130
+
131
+ #Gets the details of a VM
132
+ def self.getVMDetails(sc_connection, vmResource)
133
+
134
+ #validation
135
+ validate_sc_connection(sc_connection)
136
+ validate_resource("Virtual Machine Resource", vmResource)
137
+
138
+ response = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + vmResource )
139
+ responseBodyAsObject = JSON.parse(response.body)
140
+ name, description, storageGB, storageType, memoryMB, vCPUs, powerStatus, nodeResource, organizationResource,
141
+ operatingSystemTemplate, imageResource, disks, macAddress, deducedPrivateIps, ipMappings = ""
142
+
143
+ responseBodyAsObject.each do |item|
144
+ if item[0] == "name" then
145
+ name = item[1]
146
+ elsif item[0] == "description" then
147
+ description = item[1]
148
+ elsif item[0] == "storageGB" then
149
+ storageGB = item[1]
150
+ elsif item[0] == "storageType" then
151
+ storageType = item[1]
152
+ elsif item[0] == "memoryMB" then
153
+ memoryMB = item[1]
154
+ elsif item[0] == "vCPUs" then
155
+ vCPUs = item[1]
156
+ elsif item[0] == "powerStatus" then
157
+ powerStatus = item[1]
158
+ elsif item[0] == "nodeResource" then
159
+ nodeResource = item[1]["resourceURL"]
160
+ elsif item[0] == "organizationResource" then
161
+ organizationResource = item[1]["resourceURL"]
162
+ elsif item[0] == "operatingSystemTemplate" && !item[1].nil? then
163
+ operatingSystemTemplate = item[1]["resourceURL"]
164
+ elsif item[0] == "imageResource" then
165
+ imageResource = item[1]
166
+ elsif item[0] == "disks" then
167
+ diskArray = item[1]
168
+ disks = []
169
+ diskArray.each do |disk|
170
+ disks.push(disk["resourceURL"])
171
+ end
172
+ elsif item[0] == "macAddress" then
173
+ macAddress = item[1]
174
+ elsif item[0] == "deducedPrivateIps" then
175
+ deducedPrivateIps = item[1]
176
+ elsif item[0] == "ipMappings" then
177
+ ipMappingsArray = item[1]
178
+ ipMappings = []
179
+ ipMappingsArray.each do |ipMapping|
180
+ ipMappingToPush = IpMapping.new(ipMapping["privateIp"], ipMapping["publicIps"])
181
+ ipMappings.push(ipMappingToPush)
182
+ end
183
+ end
184
+ end
185
+
186
+ return VirtualMachine.new(name, description, storageGB, storageType, memoryMB, vCPUs, powerStatus, nodeResource, organizationResource,
187
+ operatingSystemTemplate, imageResource, disks, macAddress, deducedPrivateIps, ipMappings)
188
+ end
189
+
190
+
191
+ #Returns all public IPs on a VM
192
+ def self.getVMPublicIPs(sc_connection, vmResource)
193
+
194
+ #validation
195
+ validate_sc_connection(sc_connection)
196
+ validate_resource("Virtual Machine Resource", vmResource)
197
+
198
+ response = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + vmResource + "/publicip")
199
+ publicIps = []
200
+ responseBodyAsObject = JSON.parse(response.body)
201
+ responseBodyAsObject.each do |item|
202
+ publicIps.push(item["resourceURL"])
203
+ end
204
+ return publicIps
205
+
206
+ end
207
+
208
+
209
+
210
+ #Returns all private IPs on a VM
211
+ def self.getVMPrivateIPs(sc_connection, vmResource)
212
+
213
+ #validation
214
+ validate_sc_connection(sc_connection)
215
+ validate_resource("Virtual Machine Resource", vmResource)
216
+
217
+ response = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + vmResource + "/privateip")
218
+ privateIps = []
219
+ responseBodyAsObject = JSON.parse(response.body)
220
+ responseBodyAsObject.each do |item|
221
+ privateIps.push(item["resourceURL"])
222
+ end
223
+
224
+ return privateIps
225
+
226
+ end
227
+
228
+
229
+ #Returns the details of a VM public IP
230
+ def self.getVMPublicIpDetails(sc_connection, publicIpResource)
231
+
232
+ #validation
233
+ validate_sc_connection(sc_connection)
234
+ validate_resource("Public IP Resource", publicIpResource)
235
+
236
+ response = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + publicIpResource )
237
+ responseBodyAsObject = JSON.parse(response.body)
238
+ ipAddress, ipType, reserved, assignedTo, privateIpMapping, nodeResource, organizationResource = ""
239
+
240
+ responseBodyAsObject.each do |item|
241
+ if item[0] == "ipAddress" then
242
+ ipAddress = item[1]
243
+ elsif item[0] == "ipType" then
244
+ ipType = item[1]
245
+ elsif item[0] == "reserved" then
246
+ reserved = item[1]
247
+ elsif item[0] == "assignedTo" then
248
+ vmResourceArray = item[1]
249
+ assignedTo = []
250
+ vmResourceArray.each do |vmResource|
251
+ assignedTo.push(vmResource["resourceURL"])
252
+ end
253
+ elsif item[0] == "privateIpMapping" then
254
+ privateIpMapping = item[1]
255
+ elsif item[0] == "nodeResource" then
256
+ nodeResource = item[1]["resourceURL"]
257
+ elsif item[0] == "organizationResource" then
258
+ organizationResource = item[1]["resourceURL"]
259
+ end
260
+ end
261
+
262
+ return VmPublicIp.new(ipAddress, ipType, reserved, assignedTo, privateIpMapping, nodeResource, organizationResource)
263
+
264
+ end
265
+
266
+
267
+ # Returns the details of a VM private IP
268
+ def self.getVMPrivateIpDetails(sc_connection, privateIpResource)
269
+
270
+ #validation
271
+ validate_sc_connection(sc_connection)
272
+ validate_resource("Private IP Resource", privateIpResource)
273
+
274
+ response = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + privateIpResource )
275
+ responseBodyAsObject = JSON.parse(response.body)
276
+ ipAddress, assignedTo, publicIpMappings, nodeResource, organizationResource = ""
277
+
278
+ responseBodyAsObject.each do |item|
279
+ if item[0] == "ipAddress" then
280
+ ipAddress = item[1]
281
+ elsif item[0] == "assignedTo" then
282
+ vmResourceArray = item[1]
283
+ assignedTo = []
284
+ vmResourceArray.each do |vmResource|
285
+ assignedTo.push(vmResource["resourceURL"])
286
+ end
287
+ elsif item[0] == "publicIpMappings" then
288
+ publicIpMappings = item[1]
289
+ elsif item[0] == "nodeResource" then
290
+ nodeResource = item[1]["resourceURL"]
291
+ elsif item[0] == "organizationResource" then
292
+ organizationResource = item[1]["resourceURL"]
293
+ end
294
+ end
295
+
296
+ return VmPrivateIp.new(ipAddress, assignedTo, publicIpMappings, nodeResource, organizationResource)
297
+
298
+ end
299
+
300
+
301
+ # Assigns a public IP to a VM.
302
+ # ipFromReserved: a new IP will be assigned if set to nil
303
+ # privateIpMapping: Private ip mappings are only supported for nodes
304
+ # with custom network configurations. Should this field be set for
305
+ # nodes with a different network configuration, a 405 �Method not
306
+ # allowed� error will be returned.
307
+ def self.assignPublicIpToVM(sc_connection, vmResource, ipFromReserved, privateIpMapping)
308
+
309
+ #validation
310
+ validate_sc_connection(sc_connection)
311
+ validate_resource("Virtual Machine Resource", vmResource)
312
+ if (ipFromReserved != nil) then
313
+ raise ArgumentError, 'ipFromReserved needs to be a valid string' unless ipFromReserved.respond_to?(:to_str)
314
+ end
315
+ if (privateIpMapping != nil) then
316
+ raise ArgumentError, 'privateIpMapping needs to be a valid string' unless privateIpMapping.respond_to?(:to_str)
317
+ end
318
+
319
+ ipFromReserved = (ipFromReserved == nil) ? 'null' : '"' + ipFromReserved + '"'
320
+ privateIpMapping = (privateIpMapping == nil) ? 'null' : '"' + privateIpMapping + '"'
321
+ jsonBody = '{"ipFromReserved":' + ipFromReserved + ',"privateIpMapping":' + privateIpMapping + '}'
322
+
323
+ response = HttpClient.sendPOSTRequest( sc_connection, sc_connection.getUrl() + vmResource + "/publicip", jsonBody)
324
+
325
+ if (response.code == "202") then
326
+ responseBodyAsObject = JSON.parse(response.body)
327
+ responseBodyAsObject.each do |item|
328
+ return "202", item[1]
329
+ end
330
+ else
331
+ return response.code, response['X-Application-Error-Reference'], response['X-Application-Error-Description']
332
+ end
333
+
334
+ end
335
+
336
+
337
+
338
+
339
+ # Starts a Delete VM transaction.
340
+ # Returns the response code as well as the task resource
341
+ # if the transaction is triggered successfully.
342
+ def self.deleteVM(sc_connection, vmResource, releaseIPs)
343
+
344
+ #validation
345
+ validate_sc_connection(sc_connection)
346
+ validate_resource("Virtual Machine Resource", vmResource)
347
+
348
+ params = []
349
+
350
+ if ((releaseIPs != nil) && (releaseIPs)) then
351
+ params.push(["released","true"])
352
+ else
353
+ params.push(["released","false"])
354
+ end
355
+
356
+ response = HttpClient.sendDELETERequest( sc_connection, sc_connection.getUrl() + vmResource, params)
357
+
358
+ if (response.code == "202") then
359
+ responseBodyAsObject = JSON.parse(response.body)
360
+
361
+ responseBodyAsObject.each do |item|
362
+ return "202", item[1]
363
+ end
364
+ else
365
+ return response.code, response['X-Application-Error-Reference'], response['X-Application-Error-Description']
366
+ end
367
+
368
+ end
369
+
370
+
371
+ # Starts a Power On/Off transaction.
372
+ # Returns the response code as well as the task resource
373
+ # if the transaction is triggered successfully.
374
+ def self.powerVM(sc_connection, vmResource, powerState)
375
+
376
+ #validation
377
+ validate_sc_connection(sc_connection)
378
+ validate_resource("Virtual Machine Resource", vmResource)
379
+ raise ArgumentError, 'powerState needs to be initialized' unless powerState != nil
380
+ raise ArgumentError, 'powerState needs to be a valid string' unless powerState.respond_to?(:to_str)
381
+
382
+ params = []
383
+ params.push(["powerState", powerState])
384
+ response = HttpClient.sendPUTRequest( sc_connection, sc_connection.getUrl() + vmResource + "/power", params)
385
+
386
+ if (response.code == "202") then
387
+ responseBodyAsObject = JSON.parse(response.body)
388
+ responseBodyAsObject.each do |item|
389
+ return "202", item[1]
390
+ end
391
+ else
392
+ return response.code, response['X-Application-Error-Reference'], response['X-Application-Error-Description']
393
+ end
394
+ end
395
+
396
+
397
+ # Starts a Reboot VM transaction.
398
+ # Returns the response code as well as the task resource
399
+ # if the transaction is triggered successfully.
400
+ def self.rebootVM(sc_connection, vmResource)
401
+
402
+ #validation
403
+ validate_sc_connection(sc_connection)
404
+ validate_resource("Virtual Machine Resource", vmResource)
405
+
406
+ response = HttpClient.sendPUTRequest( sc_connection, sc_connection.getUrl() + vmResource + "/reboot")
407
+ if (response.code == "202") then
408
+ responseBodyAsObject = JSON.parse(response.body)
409
+ responseBodyAsObject.each do |item|
410
+ return "202", item[1]
411
+ end
412
+ else
413
+ return response.code, response['X-Application-Error-Reference'], response['X-Application-Error-Description']
414
+ end
415
+
416
+ end
417
+
418
+
419
+
420
+
421
+ # Returns the status of a task.
422
+ def self.getTaskStatus(sc_connection, taskResource)
423
+
424
+ #validation
425
+ raise ArgumentError, 'SecuredCloudConnection needs to be initialized' unless sc_connection != nil
426
+ raise ArgumentError, 'Task Resource needs to be initialized' unless taskResource != nil
427
+ raise ArgumentError, 'Task Resource needs to be a valid string' unless taskResource.respond_to?(:to_s)
428
+
429
+ response = HttpClient.sendGETRequest( sc_connection, sc_connection.getUrl() + taskResource )
430
+ responseBodyAsObject = JSON.parse(response.body)
431
+ percentageComplete, requestStateEnum, result, errorCode, errorMessage, latestTaskDescription, processDescription, createdTimestamp, lastUpdatedTimeStamp = ""
432
+
433
+ responseBodyAsObject.each do |item|
434
+ if item[0] == "percentageComplete" then
435
+ percentageComplete = item[1]
436
+ elsif item[0] == "requestStateEnum" then
437
+ requestStateEnum = item[1]
438
+ elsif item[0] == "result" then
439
+ result = item[1]
440
+ elsif item[0] == "errorCode" then
441
+ errorCode = item[1]
442
+ elsif item[0] == "errorMessage" then
443
+ errorMessage = item[1]
444
+ elsif item[0] == "latestTaskDescription" then
445
+ latestTaskDescription = item[1]
446
+ elsif item[0] == "processDescription" then
447
+ processDescription = item[1]
448
+ elsif item[0] == "createdTimestamp" then
449
+ createdTimestamp = item[1]
450
+ elsif item[0] == "lastUpdatedTimeStamp" then
451
+ lastUpdatedTimeStamp = item[1]
452
+ end
453
+ end
454
+
455
+ return TaskStatus.new(percentageComplete, requestStateEnum, result, errorCode, errorMessage, latestTaskDescription, processDescription, createdTimestamp, lastUpdatedTimeStamp)
456
+ end
457
+
458
+
459
+ def self.createVMJSONBody(name, description, storageGB, memoryMB, vCPUCount, powerStatus, imageResource, osTemplateResource, osPassword)
460
+
461
+ if (name == nil) then
462
+ name = 'null'
463
+ else
464
+ raise ArgumentError, 'name needs to be a valid string' unless name.respond_to?(:to_str)
465
+ name = '"' + name + '"'
466
+ end
467
+
468
+ if (description == nil) then
469
+ description = 'null'
470
+ else
471
+ raise ArgumentError, 'description needs to be a valid string' unless description.respond_to?(:to_str)
472
+ description = '"' + description + '"'
473
+ end
474
+
475
+ storageType = '"SATA"'
476
+
477
+ if (storageGB == nil) then
478
+ storageGB = 'null'
479
+ else
480
+ raise ArgumentError, 'storageGB needs to be a valid number' unless storageGB.is_a? Numeric
481
+ end
482
+
483
+ if (memoryMB == nil) then
484
+ memoryMB = 'null'
485
+ else
486
+ raise ArgumentError, 'memoryMB needs to be a valid number' unless memoryMB.is_a? Numeric
487
+ end
488
+
489
+ if (vCPUCount == nil) then
490
+ vCPUCount = 'null'
491
+ else
492
+ raise ArgumentError, 'vCPUCount needs to be a valid number' unless vCPUCount.is_a? Numeric
493
+ end
494
+
495
+ if (powerStatus == nil) then
496
+ powerStatus = 'null'
497
+ else
498
+ raise ArgumentError, 'powerStatus needs to be a valid string' unless powerStatus.respond_to?(:to_str)
499
+ powerStatus = '"' + powerStatus + '"'
500
+ end
501
+
502
+ if (imageResource == nil) then
503
+ imageResource = 'null'
504
+ else
505
+ raise ArgumentError, 'imageResource needs to be a valid string' unless imageResource.respond_to?(:to_str)
506
+ imageResource = '{"resourceURL":"' + imageResource + '"}'
507
+ end
508
+
509
+ if (osTemplateResource == nil) then
510
+ osTemplateResource = 'null'
511
+ else
512
+ raise ArgumentError, 'osTemplateResource needs to be a valid string' unless osTemplateResource.respond_to?(:to_str)
513
+ osTemplateResource = '{"resourceURL":"' + osTemplateResource + '"}'
514
+ end
515
+
516
+ if (osPassword == nil) then
517
+ osPassword = 'null'
518
+ else
519
+ raise ArgumentError, 'osPassword needs to be a valid string' unless osPassword.respond_to?(:to_str)
520
+ osPassword = '"' + osPassword + '"'
521
+ end
522
+
523
+ return '{"name":' + name + ',"description":' + description +
524
+ ',"storageGB":' + storageGB.to_s() + ',"memoryMB":' + memoryMB.to_s() +
525
+ ',"vCPUs":' + vCPUCount.to_s() + ',"storageType":' + storageType +
526
+ ',"powerStatus":' + powerStatus + ',"operatingSystemTemplate":' + osTemplateResource +
527
+ ',"newOperatingSystemAdminPassword":' + osPassword +
528
+ ',"imageResource":' + imageResource + '}'
529
+ end
530
+ private_class_method :createVMJSONBody
531
+
532
+
533
+ end
534
+
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: secured_cloud_api_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Alan Vella
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-13 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A simple API client for the Secured Cloud
14
+ email: alanv@ccbilleu.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/secured_cloud_api_client.rb
20
+ - lib/secured_cloud_api_client/http_client.rb
21
+ - lib/secured_cloud_api_client/ip_mapping.rb
22
+ - lib/secured_cloud_api_client/os_template.rb
23
+ - lib/secured_cloud_api_client/sc_connection.rb
24
+ - lib/secured_cloud_api_client/task_status.rb
25
+ - lib/secured_cloud_api_client/virtual_machine.rb
26
+ - lib/secured_cloud_api_client/vm_private_ip.rb
27
+ - lib/secured_cloud_api_client/vm_public_ip.rb
28
+ homepage: http://www.phoenixnap.com/secured-cloud/about-our-cloud/api.php
29
+ licenses:
30
+ - SecuredCloud
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 2.2.1
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Secured Cloud API Client
52
+ test_files: []