Class: ACIrb::RestClient
- Inherits:
-
Object
- Object
- ACIrb::RestClient
- Defined in:
- lib/acirb/restclient.rb
Overview
REST client end point implementation
Defined Under Namespace
Classes: ApicAuthenticationError, ApicErrorResponse
Instance Attribute Summary collapse
-
#auth_cookie ⇒ Object
readonly
Returns the value of attribute auth_cookie.
-
#baseurl ⇒ Object
Returns the value of attribute baseurl.
-
#debug ⇒ Object
Returns the value of attribute debug.
-
#format ⇒ Object
Returns the value of attribute format.
-
#password ⇒ Object
Returns the value of attribute password.
-
#refresh_time ⇒ Object
readonly
Returns the value of attribute refresh_time.
-
#user ⇒ Object
Returns the value of attribute user.
-
#verify ⇒ Object
Returns the value of attribute verify.
Instance Method Summary collapse
-
#authenticate ⇒ Object
Public: Authenticates the REST session with APIC Sends a aaaLogin message to APIC and updates the following instance variables: @auth_cookie - session cookie @refresh_time - session refresh timeout in seconds.
-
#escape(uri) ⇒ Object
Internal: Escape URI before using with APIC REST interface.
-
#get(options) ⇒ Object
Internal: Queries the APIC REST API for data.
-
#initialize(options = {}) ⇒ RestClient
constructor
Public: Initializes and establishes an authenticated session with APIC REST endpoint.
-
#lookupByClass(cls, options = {}) ⇒ Object
Public: Helper function that performs a simple lookup on a Class.
-
#lookupByDn(dn, options = {}) ⇒ Object
Public: Helper function that performs a simple lookup on a Dn.
-
#parse_error(doc) ⇒ Object
Internal: Parses for error responses in APIC response payload.
-
#parse_response(response) ⇒ Object
Internal: Parses APIC response payload into ACIrb::MO objects.
-
#post(options) ⇒ Object
Internal: Posts data to the APIC REST interface.
-
#query(query_obj) ⇒ Object
Public: Sends a query to APIC and returns the matching MO objects.
-
#refresh_session ⇒ Object
Public: Refreshes an existing RestClient object session Sends a aaaRefresh message to APIC and updates the following instance variables: @auth_cookie - session cookie @refresh_time - session refresh timeout in seconds.
-
#refresh_subscription(subscription_id) ⇒ Object
Public: Refreshes an existing subscription query.
-
#subscribe(query_obj) ⇒ Object
Public: Sends an event subscription query to APIC.
Constructor Details
#initialize(options = {}) ⇒ RestClient
Public: Initializes and establishes an authenticated session with APIC
REST endpoint
options - Hash options used to specify connectivity
attributes (default: {}):
:url - string URL of APIC, e.g., https://apic (required)
:user - string containing User ID for authentication (required)
:password - string containing Password for
authentication (required)
:debug - boolean true or false for including verbose REST output
(default: false)
:format - string 'xml' or 'json' specifying the format to use
for messaging to APIC. (default: xml)
:verify - boolean true or false for verifying the SSL
certificate. (default: false)
Examples:
rest = ACIrb::RestClient.new(url: 'https://apic', user: 'admin',
password: 'password', format: 'json',
debug: false)
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/acirb/restclient.rb', line 42 def initialize( = {}) uri = URI.parse([:url]) @baseurl = '%s://%s:%s' % [uri.scheme, uri.host, uri.port] @format = [:format] ? [:format] : 'xml' @user = [:user] @password = [:password] @verify = [:verify] @client = HTTPClient.new @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE \ unless [:verify] && uri.scheme == 'https' @debug = [:debug] @auth_cookie = '' authenticate if @user && @password end |
Instance Attribute Details
#auth_cookie ⇒ Object (readonly)
Returns the value of attribute auth_cookie.
13 14 15 |
# File 'lib/acirb/restclient.rb', line 13 def @auth_cookie end |
#baseurl ⇒ Object
Returns the value of attribute baseurl.
12 13 14 |
# File 'lib/acirb/restclient.rb', line 12 def baseurl @baseurl end |
#debug ⇒ Object
Returns the value of attribute debug.
12 13 14 |
# File 'lib/acirb/restclient.rb', line 12 def debug @debug end |
#format ⇒ Object
Returns the value of attribute format.
12 13 14 |
# File 'lib/acirb/restclient.rb', line 12 def format @format end |
#password ⇒ Object
Returns the value of attribute password.
12 13 14 |
# File 'lib/acirb/restclient.rb', line 12 def password @password end |
#refresh_time ⇒ Object (readonly)
Returns the value of attribute refresh_time.
13 14 15 |
# File 'lib/acirb/restclient.rb', line 13 def refresh_time @refresh_time end |
#user ⇒ Object
Returns the value of attribute user.
12 13 14 |
# File 'lib/acirb/restclient.rb', line 12 def user @user end |
#verify ⇒ Object
Returns the value of attribute verify.
12 13 14 |
# File 'lib/acirb/restclient.rb', line 12 def verify @verify end |
Instance Method Details
#authenticate ⇒ Object
Public: Authenticates the REST session with APIC Sends a aaaLogin message to APIC and updates the following instance variables:
@auth_cookie - session cookie
@refresh_time - session refresh timeout in seconds
Returns nothing.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/acirb/restclient.rb', line 71 def authenticate builder = Nokogiri::XML::Builder.new do |xml| xml.aaaUser(name: @user, pwd: @password) end post_url = URI.encode(@baseurl.to_s + '/api/mo/aaaLogin.xml') puts 'POST REQUEST', post_url if @debug puts 'POST BODY', builder.to_xml if @debug response = @client.post(post_url, body: builder.to_xml) puts 'POST RESPONSE: ', response.body if @debug doc = Nokogiri::XML(response.body) fail ApicAuthenticationError, 'Authentication error(%s): %s' % [doc.at_css('error')['code'], doc.at_css('error')['text']] \ if doc.at_css('error') fail ApicErrorResponse, 'Unexpected HTTP Error response code(%s): %s' % [response.code, response.body] if response.code != 200 @auth_cookie = doc.at_css('aaaLogin')['token'] @refresh_time = doc.at_css('aaaLogin')['refreshTimeoutSeconds'] end |
#escape(uri) ⇒ Object
Internal: Escape URI before using with APIC REST interface
uri - URI to escape
Returns escaped URI as string
113 114 115 |
# File 'lib/acirb/restclient.rb', line 113 def escape(uri) return URI.encode(uri, /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,]/) end |
#get(options) ⇒ Object
Internal: Queries the APIC REST API for data
options - Hash options for defining get parameters (default: {})
:url - relative URL for request (required)
Returns results of parse_response, which will be the parsed results of the XML or JSON payload represented as ACIrb::MO objects
150 151 152 153 154 155 156 157 158 |
# File 'lib/acirb/restclient.rb', line 150 def get() get_url = self.escape(@baseurl.to_s + [:url].to_s) puts 'GET REQUEST', get_url if @debug response = @client.get(get_url) puts 'GET RESPONSE: ', response.body if @debug parse_response(response) end |
#lookupByClass(cls, options = {}) ⇒ Object
Public: Helper function that performs a simple lookup on a Class
cls - string containing the class name to query (required) options - Hash options for defining query options (default: {})
:subtree - specifies the subtree query options, which can be
children, full or self
Examples
# return all L1 physical interfaces on the fabric with complete subtree
mo = rest.lookupByClass('l1PhysIf', subtree: 'full')
Returns an array of ACIrb::MO objects for the query
327 328 329 330 331 332 |
# File 'lib/acirb/restclient.rb', line 327 def lookupByClass(cls, = {}) subtree = [:subtree] cls_query = ACIrb::ClassQuery.new(cls) cls_query.subtree = subtree query(cls_query) end |
#lookupByDn(dn, options = {}) ⇒ Object
Public: Helper function that performs a simple lookup on a Dn
dn - string containing distinguished name for the object to query
(required)
options - Hash options for defining query options (default: {})
:subtree - specifies the subtree query options, which can be
children, full or self
Examples
mo = rest.lookupByDn('uni/tn-common', subtree: 'full')
Returns a single ACIrb::MO object or nil if no response for the query is received
303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'lib/acirb/restclient.rb', line 303 def lookupByDn(dn, = {}) subtree = [:subtree] dn_query = ACIrb::DnQuery.new(dn) dn_query.subtree = subtree mos = query(dn_query) if mos.length == 1 return mos[0] else return nil end end |
#parse_error(doc) ⇒ Object
Internal: Parses for error responses in APIC response payload
doc - Nokigiri XML document or Hash array containing well formed
APIC response payload (required)
164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/acirb/restclient.rb', line 164 def parse_error(doc) if format == 'xml' fail ApicErrorResponse, 'Error response from APIC (%s): "%s"' % \ [doc.at_css('error')['code'], doc.at_css('error')['text']] \ if doc.at_css('error') elsif format == 'json' fail ApicErrorResponse, 'Error response from APIC (%s): "%s"' % \ [doc['imdata'][0]['error']['attributes']['code'].to_s, \ doc['imdata'][0]['error']['attributes']['text'].to_s] \ if doc['imdata'].length > 0 && doc['imdata'][0].include?('error') end end |
#parse_response(response) ⇒ Object
Internal: Parses APIC response payload into ACIrb::MO objects
response - string containing the XML or JSON payload that will be
parsed according to the format defined at instance creation
(required)
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/acirb/restclient.rb', line 182 def parse_response(response) if format == 'xml' xml_data = response.body doc = Nokogiri::XML(xml_data) parse_error(doc) mos = [] doc.root.elements.each do |xml_obj| mo = ACIrb::Loader.load_xml(xml_obj) mos.push(mo) end return mos elsif format == 'json' json_data = response.body doc = JSON.parse(json_data) parse_error(doc) mos = [] doc['imdata'].each do |json_obj| mo = ACIrb::Loader.load_json(json_obj) mos.push(mo) end return mos end end |
#post(options) ⇒ Object
Internal: Posts data to the APIC REST interface
options - Hash options for defining post parameters (default: {})
:url - relative URL for request (required)
:data - post payload to be included in the request (required)
Returns results of parse_response, which will be the parsed results of the XML or JSON payload represented as ACIrb::MO objects
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/acirb/restclient.rb', line 125 def post() post_url = self.escape(@baseurl.to_s + [:url].to_s) data = [:data] if @format == 'xml' data = data.to_xml elsif @format == 'json' data = data.to_json end puts 'POST REQUEST', post_url if @debug puts 'POST BODY', data if @debug response = @client.post(post_url, body: data) puts 'POST RESPONSE: ', response.body if @debug parse_response(response) end |
#query(query_obj) ⇒ Object
Public: Sends a query to APIC and returns the matching MO objects
query_obj - ACIrb::Query object, typically either ACIrb::DnQuery or
ACIrb::ClassQuery which contains the query that will be issued
(required)
Examples
dn_query = ACIrb::DnQuery.new('uni/tn-common')
dn_query.subtree = 'full'
mos = rest.query(dn_query)
Returns array of ACIrb::MO objects for the query
225 226 227 228 |
# File 'lib/acirb/restclient.rb', line 225 def query(query_obj) query_uri = query_obj.uri(@format) get(url: query_uri) end |
#refresh_session ⇒ Object
Public: Refreshes an existing RestClient object session Sends a aaaRefresh message to APIC and updates the following instance variables:
@auth_cookie - session cookie
@refresh_time - session refresh timeout in seconds
Returns nothing.
95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/acirb/restclient.rb', line 95 def refresh_session get_url = URI.encode(@baseurl.to_s + '/api/mo/aaaRefresh.xml') puts 'GET REQUEST', get_url if @debug response = @client.get(get_url) puts 'GET RESPONSE: ', response.body if @debug doc = Nokogiri::XML(response.body) fail ApicAuthenticationError, 'Authentication error(%s): %s' % [doc.at_css('error')['code'], doc.at_css('error')['text']] \ if doc.at_css('error') @auth_cookie = doc.at_css('aaaLogin')['token'] @refresh_time = doc.at_css('aaaLogin')['refreshTimeoutSeconds'] end |
#refresh_subscription(subscription_id) ⇒ Object
Public: Refreshes an existing subscription query
subscription_id - string containing the subscription ID for a previously
subscribed to query
Examples
class_query = ACIrb::ClassQuery.new('fvCEp')
class_query.page_size = '1'
class_query.page = '0'
subscription_id = rest.subscribe(class_query)
sleep(50)
rest.refresh_subscription(subcription_id)
Returns nothing.
286 287 288 289 |
# File 'lib/acirb/restclient.rb', line 286 def refresh_subscription(subscription_id) query_uri = '/api/subscriptionRefresh.%s?id=%s' % [@format, subscription_id] get(url: query_uri) end |
#subscribe(query_obj) ⇒ Object
Public: Sends an event subscription query to APIC
query_obj - ACIrb::Query object, typically either ACIrb::DnQuery or
ACIrb::ClassQuery which contains the query that will be
issued. This query will have the .subscribe property set
to "yes" as part of the subscription process (required)
Examples
# subscribe to all changes on fvCEp end points on fabric
# but restrict the results of the query to only include 1
# as to reduce the initial subscription time
class_query = ACIrb::ClassQuery.new('fvCEp')
class_query.page_size = '1'
class_query.page = '0'
subscription_id = rest.subscribe(class_query)
Returns the subscription ID for the newly registered subscription
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/acirb/restclient.rb', line 247 def subscribe(query_obj) query_obj.subscribe = 'yes' query_uri = query_obj.uri(@format) get_url = self.escape(@baseurl.to_s + query_uri.to_s) puts 'GET REQUEST', get_url if @debug response = @client.get(get_url) puts 'GET RESPONSE: ', response.body if @debug if format == 'xml' xml_data = response.body doc = Nokogiri::XML(xml_data) parse_error(doc) subscriptionId = doc.at_css('imdata')['subscriptionId'] elsif format == 'json' json_data = response.body doc = JSON.parse(json_data) parse_error(doc) subscriptionId = doc['subscriptionId'] end subscriptionId end |