vcloud 0.0.1.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.
Files changed (56) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +14 -0
  3. data/Gemfile.lock +39 -0
  4. data/LICENSE +7 -0
  5. data/README.md +53 -0
  6. data/Rakefile +8 -0
  7. data/examples/hello_vcloud.rb +183 -0
  8. data/lib/vcloud.rb +16 -0
  9. data/lib/vcloud/base_vcloud_entity.rb +59 -0
  10. data/lib/vcloud/client.rb +117 -0
  11. data/lib/vcloud/constants.rb +38 -0
  12. data/lib/vcloud/errors.rb +31 -0
  13. data/lib/vcloud/parses_xml.rb +33 -0
  14. data/lib/vcloud/rest_api.rb +91 -0
  15. data/lib/vcloud/user.rb +5 -0
  16. data/lib/vcloud/user/catalog.rb +32 -0
  17. data/lib/vcloud/user/catalog_item.rb +10 -0
  18. data/lib/vcloud/user/error.rb +12 -0
  19. data/lib/vcloud/user/instantiate_vapp_template_params.rb +36 -0
  20. data/lib/vcloud/user/link.rb +30 -0
  21. data/lib/vcloud/user/network_config.rb +20 -0
  22. data/lib/vcloud/user/network_config_section.rb +20 -0
  23. data/lib/vcloud/user/org.rb +69 -0
  24. data/lib/vcloud/user/org_list.rb +10 -0
  25. data/lib/vcloud/user/reference.rb +27 -0
  26. data/lib/vcloud/user/task.rb +54 -0
  27. data/lib/vcloud/user/vapp.rb +103 -0
  28. data/lib/vcloud/user/vdc.rb +32 -0
  29. data/lib/version.rb +3 -0
  30. data/spec/catalog_item_spec.rb +35 -0
  31. data/spec/catalog_spec.rb +62 -0
  32. data/spec/client_spec.rb +87 -0
  33. data/spec/fixtures/catalog.xml +8 -0
  34. data/spec/fixtures/catalog_item.xml +6 -0
  35. data/spec/fixtures/error_login_404.html +24 -0
  36. data/spec/fixtures/instantiate_vapp_template_params.xml +11 -0
  37. data/spec/fixtures/network_config.xml +6 -0
  38. data/spec/fixtures/network_config_section.xml +6 -0
  39. data/spec/fixtures/org.xml +11 -0
  40. data/spec/fixtures/org_list.xml +4 -0
  41. data/spec/fixtures/session.xml +7 -0
  42. data/spec/fixtures/task.xml +6 -0
  43. data/spec/fixtures/vapp.xml +31 -0
  44. data/spec/fixtures/vapp_template.xml +74 -0
  45. data/spec/fixtures/vdc.xml +55 -0
  46. data/spec/instantiate_vapp_template_params_spec.rb +60 -0
  47. data/spec/network_config_section_spec.rb +42 -0
  48. data/spec/network_config_spec.rb +31 -0
  49. data/spec/org_spec.rb +99 -0
  50. data/spec/rest_api_spec.rb +48 -0
  51. data/spec/spec_helper.rb +20 -0
  52. data/spec/task_spec.rb +74 -0
  53. data/spec/vapp_spec.rb +85 -0
  54. data/spec/vdc_spec.rb +83 -0
  55. data/vcloud.gemspec +19 -0
  56. metadata +173 -0
@@ -0,0 +1,38 @@
1
+ module VCloud
2
+ module Constants
3
+
4
+ # vCloud Director API versions
5
+ module Version
6
+ V0_9 = '0.9'
7
+ V1_5 = '1.5'
8
+ V5_1 = '5.1'
9
+ end
10
+
11
+ ACCEPT_HEADER = 'application/*+xml'
12
+ XML_ENCODING = 'UTF-8'
13
+
14
+ # vCloud Director MIME types
15
+ module ContentType
16
+ CATALOG = 'application/vnd.vmware.vcloud.catalog+xml'
17
+ CATALOG_ITEM = 'application/vnd.vmware.vcloud.catalogItem+xml'
18
+ INSTANTIATE_VAPP_TEMPLATE_PARAMS = 'application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml'
19
+ NETWORK_CONFIG_SECTION = 'application/vnd.vmware.vcloud.networkConfigSection+xml'
20
+ ORG = 'application/vnd.vmware.vcloud.org+xml'
21
+ ORG_LIST = 'application/vnd.vmware.vcloud.orgList+xml'
22
+ ORG_NETWORK = 'application/vnd.vmware.vcloud.orgNetwork+xml'
23
+ TASK = 'application/vnd.vmware.vcloud.task+xml'
24
+ UNDEPLOY_VAPP_PARAMS = 'application/vnd.vmware.vcloud.undeployVAppParams+xml'
25
+ VAPP = 'application/vnd.vmware.vcloud.vApp+xml'
26
+ VAPP_TEMPLATE = 'application/vnd.vmware.vcloud.vAppTemplate+xml'
27
+ VDC = 'application/vnd.vmware.vcloud.vdc+xml'
28
+ end
29
+
30
+ # vCloud Director API XML namespaces
31
+ module NameSpace
32
+ V1_5 = 'http://www.vmware.com/vcloud/v1.5'
33
+ OVF = 'http://schemas.dmtf.org/ovf/envelope/1'
34
+ XSI = 'http://www.w3.org/2001/XMLSchema-instance'
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ module VCloud
2
+ module Errors
3
+ HTTPMessage = {
4
+ 200 => {:short_message => 'OK', :message => 'The request is valid and was completed. The response includes a document body.'},
5
+ 201 => {:short_message => 'Created', :message => 'The request is valid. The requested object was created and can be found at the URL specified in the Location header.'},
6
+ 202 => {:short_message => 'Accepted', :message => 'The request is valid and a task was created to handle it. This response is usually accompanied by a Task element.'},
7
+ 204 => {:short_message => 'No Content', :message => 'The request is valid and was completed. The response does not include a body.'},
8
+ 303 => {:short_message => 'See Other', :message => 'The response to the request can be found at the URL specified in the Location header.'},
9
+ 400 => {:short_message => 'Bad Request', :message => 'The request body is malformed, incomplete, or otherwise invalid.'},
10
+ 401 => {:short_message => 'Unauthorized', :message => 'An authorization header was expected but not found.'},
11
+ 403 => {:short_message => 'Forbidden', :message => 'The requesting user does not have adequate privileges to access one or more objects specified in the request.'},
12
+ 404 => {:short_message => 'Not Found', :message => 'One or more objects specified in the request could not be found in the specified container.'},
13
+ 405 => {:short_message => 'Method Not Allowed', :message => 'The HTTP method specified in the request is not supported for this object.'},
14
+ 500 => {:short_message => 'Internal Server Error', :message => 'The request was received but could not be completed because of an internal error at the server.'},
15
+ 501 => {:short_message => 'Not Implemented', :message => 'The server does not implement the request.'},
16
+ 503 => {:short_message => 'Service Unavailable', :message => 'One or more services needed to complete the request are not available on the server.'}
17
+ }
18
+ end
19
+
20
+ class VCloudError < StandardError
21
+ attr_reader :message, :major_error_code, :minor_error_code, :vendor_specific_error_code, :stack_trace
22
+
23
+ def initialize(message, major_error_code, minor_error_code = nil, vendor_specific_error_code = nil, stack_trace = nil)
24
+ @message = message
25
+ @major_error_code = major_error_code
26
+ @minor_error_code = minor_error_code
27
+ @vendor_specific_error_code = vendor_specific_error_code
28
+ @stack_trace = stack_trace
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ module VCloud
2
+ module ParsesXml
3
+ def self.included(base)
4
+ base.send(:include, HappyMapper)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def has_links
10
+ self.class_eval do
11
+ has_many :links, 'VCloud::Link', :xpath => '.'
12
+ end
13
+ end
14
+
15
+ def has_default_attributes
16
+ self.class_eval do
17
+ attribute :id, 'String'
18
+ attribute :type, 'String'
19
+ attribute :name, 'String'
20
+ attribute :href, 'String'
21
+ end
22
+ end
23
+
24
+ def from_xml(xml)
25
+ parse(xml)
26
+ end
27
+ end
28
+
29
+ def parse_xml(xml)
30
+ parse(xml)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,91 @@
1
+ module VCloud
2
+ module RestApi
3
+
4
+ def refresh(session = self.session)
5
+ http_opts = build_generic_http_opts(@href, nil, nil, session, {})
6
+ http_opts.merge!(:method => 'get')
7
+ http_opts[:headers][:accept] = self.class.type+";version=#{session.api_version}"
8
+ response = http_request(http_opts)
9
+ parse_response(response)
10
+ end
11
+
12
+ def create
13
+ end
14
+
15
+ def update
16
+ end
17
+
18
+ def delete(url, payload, content_type, session = self.session, opts={})
19
+ http_opts = build_generic_http_opts(url, payload, content_type, session, opts)
20
+ http_opts.merge!(:method => 'delete')
21
+ http_request(http_opts)
22
+ end
23
+
24
+ def post(url, payload, content_type, session = self.session, opts={})
25
+ http_opts = build_generic_http_opts(url, payload, content_type, session, opts)
26
+ http_opts.merge!(:method => 'post')
27
+ http_request(http_opts)
28
+ end
29
+
30
+ def http_request(http_opts)
31
+ request = RestClient::Request.new(http_opts)
32
+ response = request.execute { |response, request|
33
+ case response.code
34
+ when 200, 201, 202, 204 then
35
+ return response.body
36
+ when 303 then
37
+ # 303 See Other, provides a Location header
38
+ # TODO: How do we handle this?
39
+ return response.body
40
+ when 400, 401, 403, 404, 405, 500, 501, 503 then
41
+
42
+ # If there is a body, try to parse as Error xml doc and raise exception
43
+ if not response.body.strip.empty?
44
+ error = VCloud::Error.from_xml(response.body)
45
+ if error.instance_of?(VCloud::Error)
46
+ raise VCloud::VCloudError.new(
47
+ error.message,
48
+ error.major_error_code,
49
+ error.minor_error_code,
50
+ error.vendor_specific_error_code,
51
+ error.stack_trace)
52
+ end
53
+ end
54
+
55
+ # No body was supplied or body wasn't an Error xml doc, create and raise exception
56
+
57
+ major_error_code = response.code
58
+ short_message = VCloud::Errors::HTTPMessage[response.code][:short_message]
59
+ long_message = VCloud::Errors::HTTPMessage[response.code][:message]
60
+ message = "#{short_message} - #{long_message}"
61
+
62
+ raise VCloud::VCloudError.new(message, major_error_code)
63
+ else
64
+ raise VCloud::VCloudError.new('An unexpected return code was received', response.code)
65
+ end
66
+ }
67
+
68
+ response.nil? ? '' : response.body
69
+
70
+ rescue OpenSSL::SSL::SSLError => err
71
+ raise VCloud::VCloudError.new("Failed to verify SSL certifcate at API target URL. Either verify that the target server has a properly named SSL certificate or create the client to skip ssl verification. Eg: session = VCloud::Client.new('https://api.vcloud.com', '1.5', :verify_ssl => false)", 'na')
72
+ end
73
+
74
+ def build_generic_http_opts(url, payload, content_type, session, opts)
75
+ headers = {:accept => VCloud::Constants::ACCEPT_HEADER+";version=#{session.api_version}"}.merge(session.token)
76
+ headers.merge!(:content_type => content_type) if content_type
77
+ {
78
+ :url => url,
79
+ :payload => payload,
80
+ :verify_ssl => session.verify_ssl,
81
+ :headers => headers
82
+ }.merge(opts)
83
+ end
84
+
85
+ #override to provide custom parsing
86
+ def parse_response(response)
87
+ parse_xml(response.body)
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,5 @@
1
+ module VCloud
2
+ Dir[File.expand_path("../user/*.rb", __FILE__)].each do |file|
3
+ require file
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ module VCloud
2
+ # Contains a collection of CatalogItem references
3
+ class Catalog < BaseVCloudEntity
4
+
5
+ has_type VCloud::Constants::ContentType::CATALOG
6
+ tag 'Catalog'
7
+ has_links
8
+ has_default_attributes
9
+ wrap 'CatalogItems' do
10
+ has_many :catalog_item_references, 'VCloud::Reference', :tag => "CatalogItem"
11
+ end
12
+ element :is_published, Boolean, :tag => 'IsPublished'
13
+
14
+ # Returns a hash of of all CatalogItem references, keyed by the CatalogItem name
15
+ #
16
+ # @return [Hash{String => VCloud::Reference}] Reference to all CatalogsItems in the Catalog, keyed by name
17
+ def get_catalog_item_references_by_name
18
+ Hash[catalog_item_references.collect{ |i| [i.name, i] }]
19
+ end
20
+
21
+ # Retrieves an CatalogItem, assuming the user has access to it
22
+ #
23
+ # @param [String] name CatalogItem name
24
+ # @param [VCloud::Client] session Session to use to retrieve the CatalogItem
25
+ # @return [VCloud::CatalogItem] CatalogItem object
26
+ def get_catalog_item_from_name(name, session = self.session)
27
+ catalog_items = get_catalog_item_references_by_name
28
+ item = catalog_items[name] or return nil
29
+ CatalogItem.from_reference(item, session)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,10 @@
1
+ module VCloud
2
+ # Contains a reference to a VappTemplate or Media object and related metadata
3
+ class CatalogItem < BaseVCloudEntity
4
+ has_type VCloud::Constants::ContentType::CATALOG_ITEM
5
+ tag 'CatalogItem'
6
+ has_default_attributes
7
+ has_links
8
+ has_one :entity_reference, 'VCloud::Reference', :tag => 'Entity'
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module VCloud
2
+ class Error
3
+ include ParsesXml
4
+
5
+ tag 'Error'
6
+ attribute :message, String
7
+ attribute :major_error_code, Integer, :tag => "majorErrorCode"
8
+ attribute :minor_error_code, String, :tag => "minorErrorCode"
9
+ attribute :vendor_specific_error_code, String, :tag => "vendorSpecificErrorCode"
10
+ attribute :stack_trace, String, :tag => "stackTrace"
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ module VCloud
2
+ # Represents vApp template instantiation parameters
3
+ class InstantiateVAppTemplateParams
4
+ include ParsesXml
5
+
6
+ register_namespace 'xmlns', VCloud::Constants::NameSpace::V1_5
7
+ tag 'InstantiateVAppTemplateParams'
8
+ attribute :name, String
9
+ attribute :deploy, Boolean
10
+ attribute :power_on, Boolean, :tag => 'powerOn'
11
+ element :description, String, :tag => 'Description'
12
+ wrap 'InstantiationParams' do
13
+ has_one :network_config_section, 'VCloud::NetworkConfigSection', :tag => 'NetworkConfigSection'
14
+ end
15
+ element :source_reference, 'VCloud::Reference', :tag => 'Source'
16
+ element :is_source_delete, Boolean, :tag => 'IsSourceDelete'
17
+ element :all_eulas_accepted, Boolean, :tag => 'AllEULAsAccepted'
18
+
19
+ # A new instance of InstantiateVAppTemplateParams
20
+ #
21
+ # @param [String] name Name of the vApp
22
+ # @param [Boolean] deploy True if the vApp should be deployed at instantiation. Defaults to true.
23
+ # @param [Boolean] power_on True if the vApp should be powered-on at instantiation. Defaults to true.
24
+ # @param [String] description Description of the vApp
25
+ # @param [Boolean] all_eulas_accepted True confirms acceptance of all EULAs in a vApp template. Instantiation fails if this element is missing, empty, or set to false and one or more EulaSection elements are present.
26
+ # @param [Boolean] is_source_delete Set to true to delete the source object after the operation completes.
27
+ def initialize
28
+ @name = ''
29
+ @deploy = true
30
+ @power_on = false
31
+ @description = ''
32
+ @all_eulas_accepted = false
33
+ @is_source_delete = false
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ module VCloud
2
+ # Defines a hyper-link with a relationship, hyper-link reference, and an optional MIME type
3
+ class Link
4
+ include HappyMapper
5
+
6
+ tag 'Link'
7
+ attribute :rel, 'String'
8
+ attribute :type, 'String'
9
+ attribute :name, 'String'
10
+ attribute :href, 'String'
11
+
12
+ # A new instance of Link
13
+ #
14
+ # @param args [Hash{String => String}] Named arguments, 'rel', 'type', 'name' and 'href'
15
+ def initialize(args = {})
16
+ @rel = args[:rel]
17
+ @type = args[:type]
18
+ @name = args[:name]
19
+ @href = args[:href]
20
+ end
21
+
22
+ # Parses XML to produce a VCloud::Link
23
+ #
24
+ # @param [String] xml XML to parse
25
+ # @return [VCloud::Link] Link object parsed from the XML
26
+ def self.from_xml(xml)
27
+ parse(xml)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ module VCloud
2
+ # Represents a vApp network configuration
3
+ class NetworkConfig
4
+ include ParsesXml
5
+
6
+ tag 'NetworkConfig'
7
+ attribute :network_name, String, :tag => 'networkName'
8
+ wrap 'Configuration' do
9
+ element :parent_network_reference, 'VCloud::Reference', :tag => 'ParentNetwork'
10
+ element :fence_mode, String, :tag => 'FenceMode'
11
+ end
12
+
13
+ # Networking fence modes
14
+ module FenceMode
15
+ BRIDGED = 'bridged'
16
+ ISOLATED = 'isolated'
17
+ NAT = 'natRouted'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module VCloud
2
+ # Container for vApp networks
3
+ class NetworkConfigSection
4
+ include ParsesXml
5
+
6
+ register_namespace 'xmlns', VCloud::Constants::NameSpace::V1_5
7
+ register_namespace 'ovf', VCloud::Constants::NameSpace::OVF
8
+
9
+ tag 'NetworkConfigSection'
10
+ attribute :href, String
11
+ attribute :type, String
12
+ element :info, String, :tag => 'Info', :namespace => 'ovf'
13
+ has_many :network_configs, 'VCloud::NetworkConfig', :tag => 'NetworkConfig'
14
+
15
+ def initialize
16
+ @info = 'Configuration parameters for logical networks'
17
+ @network_configs = []
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,69 @@
1
+ module VCloud
2
+ # An org contains links to VDCs, Catalogs, and Org Networks
3
+ class Org < BaseVCloudEntity
4
+
5
+ has_type VCloud::Constants::ContentType::ORG
6
+ tag 'Org'
7
+ has_links
8
+ has_default_attributes
9
+ element :description, String, :tag => "Description"
10
+ element :full_name, String, :tag => "FullName"
11
+
12
+ # Returns all links to VDCs
13
+ #
14
+ # @return [Array<VCloud::Link>] Array of Links to VDCs
15
+ def vdc_links
16
+ @links.select {|l| l.type == VCloud::Constants::ContentType::VDC}
17
+ end
18
+
19
+ # Returns all links to Catalogs
20
+ #
21
+ # @return [Array<VCloud::Link>] Array of Links to Catalogs
22
+ def catalog_links
23
+ @links.select {|l| l.type == VCloud::Constants::ContentType::CATALOG}
24
+ end
25
+
26
+ # Returns all links to OrgNetworks
27
+ #
28
+ # @return [Array<VCloud::Link>] Array of Links to OrgNetworks
29
+ def org_network_links
30
+ @links.select {|l| l.type == VCloud::Constants::ContentType::ORG_NETWORK}
31
+ end
32
+
33
+ # Returns a hash of of all Catalog links keyed by the Catalog name
34
+ #
35
+ # @return [Hash{String => VCloud::Link}] Links to all Catalogs in the Org, keyed by name
36
+ def get_catalog_links_by_name
37
+ Hash[catalog_links.collect { |l| [l.name, l] }]
38
+ end
39
+
40
+ # Retrieves an Catalog, assuming the user has access to it
41
+ #
42
+ # @param [String] name Catalog name
43
+ # @param [VCloud::Client] session Session to use to retrieve the Catalog
44
+ # @return [VCloud::Catalog] Catalog object
45
+ def get_catalog_from_name(name, session = self.session)
46
+ catalogs = get_catalog_links_by_name
47
+ link = catalogs[name] or return nil
48
+ Catalog.from_reference(link, session)
49
+ end
50
+
51
+ # Returns a hash of of all VDCs links keyed by the Catalog name
52
+ #
53
+ # @return [Hash{String => VCloud::Link}] Links to all VDCs in the Org, keyed by name
54
+ def get_vdc_links_by_name
55
+ Hash[vdc_links.collect { |l| [l.name, l] }]
56
+ end
57
+
58
+ # Retrieves a VDC, assuming the user has access to it
59
+ #
60
+ # @param [String] name VDC name
61
+ # @param [VCloud::Client] session Session to use to retrieve the VDC
62
+ # @return [VCloud::Vdc] VDC object
63
+ def get_vdc_from_name(name, session = self.session)
64
+ links = get_vdc_links_by_name
65
+ link = links[name] or return nil
66
+ Vdc.from_reference(link, session)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,10 @@
1
+ module VCloud
2
+ # Represents a list of organizations
3
+ class OrgList < BaseVCloudEntity
4
+ include ParsesXml
5
+ has_type VCloud::Constants::ContentType::ORG_LIST
6
+ has_default_attributes
7
+ tag 'OrgList'
8
+ has_many :org_references, 'VCloud::Reference', :tag => 'Org'
9
+ end
10
+ end