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

Sign up to get free protection for your applications and to get access to all the features.
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