occi-api 4.2.0.beta.4 → 4.2.0.beta.6

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/occi-api.rb CHANGED
@@ -4,9 +4,13 @@ require 'rubygems/package'
4
4
  require 'occi-core'
5
5
 
6
6
  module Occi::Api; end
7
+ module Occi::Api::Client; end
8
+ module Occi::Api::Dsl; end
9
+ module Occi::Api::Client::Errors; end
7
10
 
8
11
  require 'occi/api/version'
9
- require 'occi/api/client/client_base'
12
+ require 'occi/api/client/authn_utils'
10
13
  require 'occi/api/client/errors'
14
+ require 'occi/api/client/client_base'
11
15
  require 'occi/api/client/client_http'
12
16
  require 'occi/api/dsl'
@@ -4,84 +4,92 @@ if defined? JRUBY_VERSION
4
4
  require 'java'
5
5
  end
6
6
 
7
- module Occi
8
- module Api
9
- module Client
10
-
11
- class AuthnUtils
12
- CERT_REGEXP = /\n?(-----BEGIN CERTIFICATE-----\n.+?\n-----END CERTIFICATE-----)\n/m
13
-
14
- # Reads credentials from a PKCS#12 compliant file. Returns
15
- # X.509 certificate and decrypted private key in PEM
16
- # formatted string.
17
- #
18
- # @example
19
- # extract_pem_from_pkcs12 "~/.globus/usercert.p12", "123456"
20
- # # => #<String>
21
- #
22
- # @param [String] Path to a PKCS#12 file with credentials
23
- # @param [String] Password needed to unlock the PKCS#12 file
24
- # @return [String] Decrypted credentials in a PEM formatted string
25
- def self.extract_pem_from_pkcs12(path_to_p12_file, p12_password)
26
- # decode certificate and its private key
27
- pem_from_pkcs12 = ""
28
- if defined? JRUBY_VERSION
29
- # Java-based Ruby, read PKCS12 manually
30
- # using KeyStore
31
- keystore = Java::JavaSecurity::KeyStore.getInstance("PKCS12")
32
- p12_input_stream = Java::JavaIo::FileInputStream.new(path_to_p12_file)
33
- pass_char_array = Java::JavaLang::String.new(p12_password).to_char_array
34
-
35
- # load and unlock PKCS#12 store
36
- keystore.load p12_input_stream, pass_char_array
37
-
38
- # read the first certificate and PK
39
- cert = keystore.getCertificate("1")
40
- pk = keystore.getKey("1", pass_char_array)
41
-
42
- pem_from_pkcs12 << "-----BEGIN CERTIFICATE-----\n"
43
- pem_from_pkcs12 << Java::JavaxXmlBind::DatatypeConverter.printBase64Binary(cert.getEncoded())
44
- pem_from_pkcs12 << "\n-----END CERTIFICATE-----"
45
-
46
- pem_from_pkcs12 << "\n"
47
-
48
- pem_from_pkcs12 << "-----BEGIN PRIVATE KEY-----\n"
49
- pem_from_pkcs12 << Java::JavaxXmlBind::DatatypeConverter.printBase64Binary(pk.getEncoded())
50
- pem_from_pkcs12 << "\n-----END PRIVATE KEY-----"
51
- else
52
- # C-based Ruby, use OpenSSL::PKCS12
53
- pkcs12 = OpenSSL::PKCS12.new(
54
- File.open(
55
- path_to_p12_file,
56
- 'rb'
57
- ),
58
- p12_password
59
- )
60
-
61
- # store cert and private key in a single PEM formatted string
62
- pem_from_pkcs12 << pkcs12.certificate.to_pem << pkcs12.key.to_pem
63
- end
64
-
65
- pem_from_pkcs12
66
- end
67
-
68
- # Reads X.509 certificates from a file to an array.
69
- #
70
- # @example
71
- # certs_to_file_ary "~/.globus/usercert.pem"
72
- # # => [#<String>, #<String>, ...]
73
- #
74
- # @param [String] Path to a PEM file containing certificates
75
- # @return [Array<String>] An array of read certificates
76
- def self.certs_to_file_ary(ca_file)
77
- # TODO: read and separate multiple certificates
78
- certs_str = File.open(ca_file).read
79
-
80
- certs_ary = certs_str.scan(CERT_REGEXP)
81
- certs_ary ? certs_ary.flatten : []
82
- end
7
+ module Occi::Api::Client
8
+
9
+ class AuthnUtils
10
+
11
+ CERT_REGEXP = /\n?(-----BEGIN CERTIFICATE-----\n.+?\n-----END CERTIFICATE-----)\n/m
12
+
13
+ # Reads credentials from a PKCS#12 compliant file. Returns
14
+ # X.509 certificate and decrypted private key in PEM
15
+ # formatted string.
16
+ #
17
+ # @example
18
+ # AuthnUtils.extract_pem_from_pkcs12 "~/.globus/usercert.p12", "123456"
19
+ # # => #<String>
20
+ #
21
+ # @param [String] Path to a PKCS#12 file with credentials
22
+ # @param [String] Password needed to unlock the PKCS#12 file
23
+ # @return [String] Decrypted credentials in a PEM formatted string
24
+ def self.extract_pem_from_pkcs12(path_to_p12_file, p12_password)
25
+ # decode certificate and its private key
26
+ if defined? JRUBY_VERSION
27
+ extract_pem_from_pkcs12_java(path_to_p12_file, p12_password)
28
+ else
29
+ extract_pem_from_pkcs12_c(path_to_p12_file, p12_password)
83
30
  end
31
+ end
32
+
33
+ def self.extract_pem_from_pkcs12_java(path_to_p12_file, p12_password)
34
+ # Java-based Ruby, read PKCS12 manually
35
+ # using KeyStore
36
+ keystore = Java::JavaSecurity::KeyStore.getInstance("PKCS12")
37
+ p12_input_stream = Java::JavaIo::FileInputStream.new(path_to_p12_file)
38
+ pass_char_array = Java::JavaLang::String.new(p12_password).to_char_array
39
+
40
+ # load and unlock PKCS#12 store
41
+ keystore.load p12_input_stream, pass_char_array
42
+
43
+ # read the first certificate and PK
44
+ cert = keystore.getCertificate("1")
45
+ pk = keystore.getKey("1", pass_char_array)
46
+
47
+ pem_from_pkcs12 = ""
48
+
49
+ pem_from_pkcs12 << "-----BEGIN CERTIFICATE-----\n"
50
+ pem_from_pkcs12 << Java::JavaxXmlBind::DatatypeConverter.printBase64Binary(cert.getEncoded())
51
+ pem_from_pkcs12 << "\n-----END CERTIFICATE-----"
52
+
53
+ pem_from_pkcs12 << "\n"
54
+
55
+ pem_from_pkcs12 << "-----BEGIN PRIVATE KEY-----\n"
56
+ pem_from_pkcs12 << Java::JavaxXmlBind::DatatypeConverter.printBase64Binary(pk.getEncoded())
57
+ pem_from_pkcs12 << "\n-----END PRIVATE KEY-----"
84
58
 
59
+ pem_from_pkcs12
85
60
  end
61
+
62
+ def self.extract_pem_from_pkcs12_c(path_to_p12_file, p12_password)
63
+ # C-based Ruby, use OpenSSL::PKCS12
64
+ pem_from_pkcs12 = ""
65
+
66
+ pkcs12 = OpenSSL::PKCS12.new(
67
+ File.open(path_to_p12_file, 'rb'),
68
+ p12_password
69
+ )
70
+
71
+ # store cert and private key in a single PEM formatted string
72
+ pem_from_pkcs12 << pkcs12.certificate.to_pem << pkcs12.key.to_pem
73
+
74
+ pem_from_pkcs12
75
+ end
76
+
77
+ # Reads X.509 certificates from a file to an array.
78
+ #
79
+ # @example
80
+ # AuthnUtils.certs_to_file_ary "~/.globus/usercert.pem"
81
+ # # => [#<String>, #<String>, ...]
82
+ #
83
+ # @param [String] Path to a PEM file containing certificates
84
+ # @return [Array<String>] An array of read certificates
85
+ def self.certs_to_file_ary(ca_file)
86
+ # TODO: read and separate multiple certificates
87
+ certs_str = File.open(ca_file).read
88
+
89
+ certs_ary = certs_str.scan(CERT_REGEXP)
90
+ certs_ary ? certs_ary.flatten : []
91
+ end
92
+
86
93
  end
94
+
87
95
  end
@@ -0,0 +1,54 @@
1
+ module Occi::Api::Client
2
+ module Base
3
+
4
+ module CategoryMethods
5
+
6
+ # Retrieves all available category types.
7
+ #
8
+ # @example
9
+ # client.get_category_types # => [ "entity", "resource", "link" ]
10
+ #
11
+ # @return [Array<String>] list of available category types in a human-readable format
12
+ def get_category_types
13
+ @model.categories.to_a.collect { |category| category.term }
14
+ end
15
+
16
+ # Retrieves all available category type identifiers.
17
+ #
18
+ # @example
19
+ # client.get_category_type_identifiers
20
+ # # => [ "http://schemas.ogf.org/occi/core#entity",
21
+ # # "http://schemas.ogf.org/occi/core#resource",
22
+ # # "http://schemas.ogf.org/occi/core#link" ]
23
+ #
24
+ # @return [Array<String>] list of available category type identifiers
25
+ def get_category_type_identifiers
26
+ @model.categories.to_a.collect { |category| category.type_identifier }
27
+ end
28
+
29
+ # Retrieves available category type identifier for the given category type.
30
+ #
31
+ # @example
32
+ # client.get_category_type_identifier("compute")
33
+ # # => 'http://schemas.ogf.org/occi/infrastructure#compute'
34
+ #
35
+ # @return [String, nil] category type identifier for the given category type
36
+ def get_category_type_identifier(type)
37
+ return type if (type =~ URI::ABS_URI) || (type && type.start_with?('/'))
38
+
39
+ cats = @model.categories.to_a.select { |k| k.term == type }
40
+ tis = cats.collect { |c| c.type_identifier }
41
+ tis.uniq!
42
+
43
+ if tis.length > 1
44
+ raise Occi::Api::Client::Errors::AmbiguousNameError,
45
+ "Category type #{type.inspect} is ambiguous, use a type identifier!"
46
+ end
47
+
48
+ tis.first
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,172 @@
1
+ module Occi::Api::Client
2
+ module Base
3
+
4
+ module EntityMethods
5
+
6
+ # Creates a new resource instance, resource should be specified
7
+ # by its name or identifier.
8
+ #
9
+ # @example
10
+ # client.get_resource "compute" # => Occi::Core::Resource
11
+ # client.get_resource "storage" # => Occi::Core::Resource
12
+ # client.get_resource "http://schemas.ogf.org/occi/infrastructure#network"
13
+ # # => Occi::Core::Resource
14
+ #
15
+ # @param [String] resource name or resource identifier
16
+ # @return [Occi::Core::Resource] new resource instance
17
+ def get_resource(resource_type)
18
+ Occi::Log.debug("Instantiating #{resource_type.inspect}")
19
+
20
+ type_id = get_resource_type_identifier(resource_type)
21
+ raise "Unknown resource type! #{resource_type.inspect}" unless type_id
22
+
23
+ new_resource = Occi::Core::Resource.new(type_id)
24
+ new_resource.model = @model
25
+
26
+ new_resource
27
+ end
28
+
29
+ # Retrieves all available entity types.
30
+ #
31
+ # @example
32
+ # client.get_entity_types # => [ "entity", "resource", "link" ]
33
+ #
34
+ # @return [Array<String>] list of available entity types in a human-readable format
35
+ def get_entity_types
36
+ collection = @model.get(Occi::Core::Entity.kind.type_identifier)
37
+ collection.kinds.to_a.collect { |kind| kind.term }
38
+ end
39
+
40
+ # Retrieves all available entity type identifiers.
41
+ #
42
+ # @example
43
+ # client.get_kind_type_identifiers
44
+ # # => [ "http://schemas.ogf.org/occi/core#entity",
45
+ # # "http://schemas.ogf.org/occi/core#resource",
46
+ # # "http://schemas.ogf.org/occi/core#link" ]
47
+ #
48
+ # @return [Array<String>] list of available entity types in a OCCI ID format
49
+ def get_entity_type_identifiers
50
+ get_kind_type_identifiers_related_to Occi::Core::Entity.kind.type_identifier
51
+ end
52
+
53
+ # Retrieves available entity type identifier for the given entity type.
54
+ #
55
+ # @example
56
+ # client.get_entity_type_identifier("compute")
57
+ # # => 'http://schemas.ogf.org/occi/infrastructure#compute'
58
+ #
59
+ # @return [String, nil] entity type identifier for the given entity type
60
+ def get_entity_type_identifier(type)
61
+ return type if (type =~ URI::ABS_URI) || (type && type.start_with?('/'))
62
+
63
+ collection = @model.get(Occi::Core::Entity.kind.type_identifier)
64
+ e_kinds = collection.kinds.to_a.select { |e| e.term == type }
65
+ tis = e_kinds.collect { |e| e.type_identifier }
66
+ tis.uniq!
67
+
68
+ if tis.length > 1
69
+ raise Occi::Api::Client::Errors::AmbiguousNameError,
70
+ "Entity type #{type.inspect} is ambiguous, use a type identifier!"
71
+ end
72
+
73
+ tis.first
74
+ end
75
+
76
+ # Retrieves all available resource types.
77
+ #
78
+ # @example
79
+ # client.get_resource_types # => [ "compute", "storage", "network" ]
80
+ #
81
+ # @return [Array<String>] list of available resource types in a human-readable format
82
+ def get_resource_types
83
+ collection = @model.get(Occi::Core::Resource.kind.type_identifier)
84
+ collection.kinds.to_a.collect { |kind| kind.term }
85
+ end
86
+
87
+ # Retrieves all available resource type identifiers.
88
+ #
89
+ # @example
90
+ # client.get_resource_type_identifiers
91
+ # # => [ "http://schemas.ogf.org/occi/infrastructure#compute",
92
+ # # "http://schemas.ogf.org/occi/infrastructure#storage",
93
+ # # "http://schemas.ogf.org/occi/infrastructure#network" ]
94
+ #
95
+ # @return [Array<String>] list of available resource types in a Occi ID format
96
+ def get_resource_type_identifiers
97
+ get_kind_type_identifiers_related_to Occi::Core::Resource.kind.type_identifier
98
+ end
99
+
100
+ # Retrieves available resource type identifier for the given resource type.
101
+ #
102
+ # @example
103
+ # client.get_resource_type_identifier("compute")
104
+ # # => 'http://schemas.ogf.org/occi/infrastructure#compute'
105
+ #
106
+ # @return [String, nil] resource type identifier for the given resource type
107
+ def get_resource_type_identifier(type)
108
+ return type if (type =~ URI::ABS_URI) || (type && type.start_with?('/'))
109
+
110
+ collection = @model.get(Occi::Core::Resource.kind.type_identifier)
111
+ r_kinds = collection.kinds.to_a.select { |r| r.term == type }
112
+ tis = r_kinds.collect { |r| r.type_identifier }
113
+ tis.uniq!
114
+
115
+ if tis.length > 1
116
+ raise Occi::Api::Client::Errors::AmbiguousNameError,
117
+ "Resource type #{type.inspect} is ambiguous, use a type identifier!"
118
+ end
119
+
120
+ tis.first
121
+ end
122
+
123
+ # Retrieves all available link types.
124
+ #
125
+ # @example
126
+ # client.get_link_types # => [ "storagelink", "networkinterface" ]
127
+ #
128
+ # @return [Array<String>] list of available link types in a human-readable format
129
+ def get_link_types
130
+ collection = @model.get(Occi::Core::Link.kind.type_identifier)
131
+ collection.kinds.to_a.collect { |kind| kind.term }
132
+ end
133
+
134
+ # Retrieves all available link type identifiers.
135
+ #
136
+ # @example
137
+ # client.get_link_type_identifiers
138
+ # # => [ "http://schemas.ogf.org/occi/infrastructure#storagelink",
139
+ # # "http://schemas.ogf.org/occi/infrastructure#networkinterface" ]
140
+ #
141
+ # @return [Array<String>] list of available link types in a OCCI ID format
142
+ def get_link_type_identifiers
143
+ get_kind_type_identifiers_related_to Occi::Core::Link.kind.type_identifier
144
+ end
145
+
146
+ # Retrieves available link type identifier for the given link type.
147
+ #
148
+ # @example
149
+ # client.get_link_type_identifier("storagelink")
150
+ # # => 'http://schemas.ogf.org/occi/infrastructure#storagelink'
151
+ #
152
+ # @return [String, nil] link type identifier for the given link type
153
+ def get_link_type_identifier(type)
154
+ return type if (type =~ URI::ABS_URI) || (type && type.start_with?('/'))
155
+
156
+ collection = @model.get(Occi::Core::Link.kind.type_identifier)
157
+ l_kinds = collection.kinds.to_a.select { |r| r.term == type }
158
+ tis = l_kinds.collect { |r| r.type_identifier }
159
+ tis.uniq!
160
+
161
+ if tis.length > 1
162
+ raise Occi::Api::Client::Errors::AmbiguousNameError,
163
+ "Link type #{type.inspect} is ambiguous, use a type identifier!"
164
+ end
165
+
166
+ tis.first
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,91 @@
1
+ module Occi::Api::Client
2
+ module Base
3
+
4
+ module Helpers
5
+
6
+ # Returns the path for a given kind type identifier
7
+ #
8
+ # @example
9
+ # path_for_kind_type_identifier "http://schemas.ogf.org/occi/infrastructure#compute"
10
+ # # => "/compute/"
11
+ # path_for_kind_type_identifier "http://localhost:3300/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
12
+ # # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
13
+ #
14
+ # @param [String] kind type identifier
15
+ # @return [String]
16
+ def path_for_kind_type_identifier(kind_type_identifier)
17
+ raise ArgumentError,
18
+ "Kind type identifier is a required argument!" if kind_type_identifier.blank?
19
+
20
+ if kind_type_identifier.start_with?(@endpoint.to_s) || kind_type_identifier.start_with?('/')
21
+ #we got an instance link
22
+ return sanitize_instance_link(kind_type_identifier)
23
+ end
24
+
25
+ kind_type_id = get_kind_type_identifier(kind_type_identifier)
26
+ unless kind_type_id
27
+ raise ArgumentError,
28
+ "There is no such kind type registered in the model! #{kind_type_identifier.inspect}"
29
+ end
30
+
31
+ kinds = @model.kinds.select { |kind| kind.type_identifier == kind_type_id }
32
+ path_for_instance(kinds.first)
33
+ end
34
+
35
+ # Returns the path for a given instance, instances not providing
36
+ # path information will raise an exception.
37
+ #
38
+ # @example
39
+ # path_for_instance Occi::Infrastructure::Network.new
40
+ # # => "/network/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
41
+ # path_for_instance Occi::Infrastructure::Compute.new
42
+ # # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
43
+ # path_for_instance Occi::Core::Mixin.new
44
+ # # => "/mixin/my_mixin/"
45
+ # path_for_instance Occi::Infrastructure::Storagelink.new
46
+ # # => "/link/storagelink/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
47
+ #
48
+ # @param [Object] instance
49
+ # @return [String] path for the given instance
50
+ def path_for_instance(instance)
51
+ unless instance.respond_to?(:location)
52
+ raise Occi::Api::Client::Errors::TypeMismatchError,
53
+ "Expected an instance responding to #location, " \
54
+ "got #{instance.class.name.inspect}"
55
+ end
56
+
57
+ if instance.location.blank?
58
+ raise Occi::Api::Client::Errors::LocationError,
59
+ "Instance of #{instance.class.name.inspect} has " \
60
+ "an empty location"
61
+ end
62
+
63
+ instance.location
64
+ end
65
+
66
+ # Extracts path from an instance link. It will remove the leading @endpoint
67
+ # and replace it with a slash.
68
+ #
69
+ # @example
70
+ # sanitize_instance_link "http://localhost:3300/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
71
+ # # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
72
+ # sanitize_instance_link "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
73
+ # # => "/compute/35ad4f45gsf-gsfg524s6gsfg-sfgsf4gsfg"
74
+ #
75
+ # @param [String] string containing the full instance link
76
+ # @return [String] extracted path, with a leading slash
77
+ def sanitize_instance_link(instance_link)
78
+ # everything starting with '/' is considered to be a resource path
79
+ return instance_link if instance_link.start_with? '/'
80
+
81
+ unless instance_link.start_with?(@endpoint.to_s)
82
+ raise ArgumentError, "Resource link #{instance_link.inspect} is not valid!"
83
+ end
84
+
85
+ URI(instance_link).request_uri
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+ end