@@ -21,9 +21,13 @@ class ManagerNet(object):
21
21
username = ''
22
22
password = ''
23
23
hostname = ''
24
- client_id = "caa87d9a-8cd7-4686-8b6e-ee2cdc5ee267"
25
- client_secret = "3ecff363-7eb3-44be-9e07-6d4386c48b0b"
24
+ default_client_id = "caa87d9a-8cd7-4686-8b6e-ee2cdc5ee267"
25
+ default_client_secret = "3ecff363-7eb3-44be-9e07-6d4386c48b0b"
26
+ client_id = default_client_id
27
+ client_secret = default_client_secret
26
28
grant_type = 'password'
29
+ cm_token = None # Cloud manager access token
30
+ cm_token_expires = 0 # Cloud manager access token expiration
27
31
token = None
28
32
token_expires = 0
29
33
max_frequency = 600
@@ -43,7 +47,7 @@ def __init__(self, config, trawler):
43
47
self .namespace = config .get ('namespace' , 'default' )
44
48
# Maximum frequency to pull data from APIC
45
49
self .max_frequency = int (config .get ('frequency' , 600 ))
46
- self .grant_type = config .get ('grant_type' , 'password' )
50
+ # self.grant_type = config.get('grant_type', 'password')
47
51
self .org_metrics = (config .get ('process_org_metrics' , 'true' ) == 'true' )
48
52
self .version = Gauge ('apiconnect_build_info' ,
49
53
"A metric with a constant '1' value labeled with API Connect version details" ,
@@ -54,7 +58,15 @@ def __init__(self, config, trawler):
54
58
self .load_credentials_from_secret (
55
59
config .get ('secret' ),
56
60
config .get ('secret_namespace' , self .namespace ))
57
- else :
61
+
62
+ if 'cloud_manager_secret' in config :
63
+ # If config points to a secret, then load from that
64
+ # either in this namespace, or the specified one
65
+ self .load_credentials_from_secret (
66
+ config .get ('cloud_manager_secret' ),
67
+ config .get ('secret_namespace' , self .namespace ))
68
+
69
+ if not 'secret' in config and not 'cloud_manager_secret' in config :
58
70
# Cloud manager username to use for REST calls
59
71
self .username = config .get ('username' , 'admin' )
60
72
if self .grant_type == 'client_credentials' :
@@ -63,9 +75,11 @@ def __init__(self, config, trawler):
63
75
else :
64
76
# Load password from secret `cloudmanager_password`
65
77
self .password = trawler .read_secret ('cloudmanager_password' )
78
+
66
79
if self .password is None :
67
80
# Use out of box default password
68
81
self .password = 'admin'
82
+
69
83
self .hostname = self .find_hostname ()
70
84
logger .debug ("Hostname found is {}" .format (self .hostname ))
71
85
self .trawler = trawler
@@ -87,6 +101,7 @@ def load_credentials_from_secret(self, secret_name, namespace):
87
101
if 'client_secret' in secrets_response .data :
88
102
self .client_secret = base64 .b64decode (secrets_response .data ['client_secret' ]).decode ('utf-8' )
89
103
self .client_id = base64 .b64decode (secrets_response .data ['client_id' ]).decode ('utf-8' )
104
+ self .grant_type = 'client_credentials'
90
105
logger .info ("Client ID to use is {}, Client Secret length is {}" .format (self .client_id , len (self .client_secret )))
91
106
92
107
except client .rest .ApiException as e :
@@ -128,6 +143,9 @@ def find_hostname(self):
128
143
logger .exception (e )
129
144
130
145
def get_webhook_status (self ):
146
+ """Get the webhook data from the API Manager
147
+ This requires cloud manager access
148
+ """
131
149
logger .info ("Getting webhook data from API Manager" )
132
150
try :
133
151
url = "https://{}/api/cloud/webhooks" .format (self .hostname )
@@ -136,7 +154,7 @@ def get_webhook_status(self):
136
154
headers = {
137
155
"Accept" : "application/json" ,
138
156
"Content-Type" : "application/json" ,
139
- "Authorization" : "Bearer {}" .format (self .token ),
157
+ "Authorization" : "Bearer {}" .format (self .cm_token ),
140
158
},
141
159
verify = False
142
160
)
@@ -200,6 +218,10 @@ def fish(self):
200
218
logger .debug ("Disabled because a fatal error already occurred" )
201
219
return
202
220
221
+ # Allow 10 seconds to run
222
+ if self .cm_token_expires - 10 < time .time ():
223
+ self .get_token (self .hostname , cloud_manager = True )
224
+
203
225
# Allow 10 seconds to run
204
226
if self .token_expires - 10 < time .time ():
205
227
self .get_token (self .hostname )
@@ -214,6 +236,7 @@ def fish(self):
214
236
logger .debug (self .data )
215
237
else :
216
238
logger .warning ("No token" )
239
+
217
240
if 'counts' in self .data :
218
241
for object_type in self .data ['counts' ]:
219
242
logger .debug ("Type: {}, Value: {}" .format (object_type , self .data ['counts' ][object_type ]))
@@ -223,6 +246,7 @@ def fish(self):
223
246
if org ['org_type' ] != 'admin' :
224
247
for catalog in org ['catalogs' ]['results' ]:
225
248
self .process_org_metrics (org ['name' ], catalog ['name' ])
249
+
226
250
self .get_webhook_status ()
227
251
228
252
@alog .timed_function (logger .trace )
@@ -273,7 +297,13 @@ def process_org_metrics(self, org_name, catalog_name):
273
297
274
298
# Get the authorization bearer token
275
299
# See https://chrisphillips-cminion.github.io/apiconnect/2019/09/18/GettingoAuthTokenFromAPIC.html
276
- def get_token (self , host ):
300
+ def get_token (self , host , cloud_manager = False ):
301
+ """Get the auth token from API Manager or Cloud Manager
302
+ API Manager requires client credentials, client_id and client_secret
303
+ Cloud Manager requires username and password, along with the known client_id and client_secret
304
+ The secret in the config could be either grant_type client_credentials or password,
305
+ but cloud manager access is always requried to be grant_type password.
306
+ """
277
307
logger .debug ("Getting bearer token" )
278
308
279
309
headers = {'Content-Type' : 'application/json' , 'Accept' : 'application/json' }
@@ -284,6 +314,12 @@ def get_token(self, host):
284
314
data ['username' ] = self .username
285
315
data ['password' ] = self .password
286
316
data ['realm' ] = 'admin/default-idp-1'
317
+ if cloud_manager :
318
+ data ['client_id' ] = self .default_client_id
319
+ data ['client_secret' ] = self .default_client_secret
320
+ data ['username' ] = self .username
321
+ data ['password' ] = self .password
322
+ data ['realm' ] = 'admin/default-idp-1'
287
323
288
324
url = "https://{}/api/token" .format (host )
289
325
response = requests .post (
@@ -293,10 +329,19 @@ def get_token(self, host):
293
329
verify = False )
294
330
295
331
if response .status_code == 200 :
332
+ token_expires = 0
333
+ token_type = "Token"
296
334
json_data = response .json ()
297
- self .token = json_data ['access_token' ]
298
- self .token_expires = json_data ['expires_in' ] + time .time ()
299
- logger .info ("Token expires at {} UTC" .format (datetime .datetime .utcfromtimestamp (int (self .token_expires ))))
335
+ if cloud_manager :
336
+ self .cm_token = json_data ['access_token' ]
337
+ self .cm_token_expires = json_data ['expires_in' ] + time .time ()
338
+ token_expires = self .cm_token_expires
339
+ token_type = "Cloud Manager Token"
340
+ else :
341
+ self .token = json_data ['access_token' ]
342
+ self .token_expires = json_data ['expires_in' ] + time .time ()
343
+ token_expires = self .token_expires
344
+ logger .info ("{} expires at {} UTC" .format (token_type , datetime .datetime .utcfromtimestamp (int (token_expires ))))
300
345
else :
301
346
logger .error ("Disabled manager net as failed to get bearer token: {}" .format (response .status_code ))
302
347
self .errored = True
0 commit comments