Merge bootstack-ops:plus65_retry into bootstack-ops:master

Proposed by Giuseppe Petralia
Status: Merged
Approved by: David O Neill
Approved revision: ad2d84ff1a67cf43e543877dc2af1145471e1872
Merged at revision: 58aaa04c3d7d1b2e8486ed007f41af74e3936542
Proposed branch: bootstack-ops:plus65_retry
Merge into: bootstack-ops:master
Diff against target: 167 lines (+56/-29)
1 file modified
bootstack-ops/cloud_report.py (+56/-29)
Reviewer Review Type Date Requested Status
David O Neill (community) Approve
Review via email: mp+365904@code.launchpad.net

Commit message

Add sleep retry on MAAS connection errors

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
David O Neill (dmzoneill) :
review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 58aaa04c3d7d1b2e8486ed007f41af74e3936542

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/bootstack-ops/cloud_report.py b/bootstack-ops/cloud_report.py
index df3fdc6..f13a5d3 100644
--- a/bootstack-ops/cloud_report.py
+++ b/bootstack-ops/cloud_report.py
@@ -50,6 +50,7 @@ from gevent.pywsgi import WSGIServer
50from maas.client.viscera.controllers import RackController, RegionController50from maas.client.viscera.controllers import RackController, RegionController
51from oauthlib import oauth151from oauthlib import oauth1
52import requests52import requests
53from aiohttp.client_exceptions import ServerDisconnectedError
5354
5455
55JUJU_DATA = os.environ.get('JUJU_DATA')56JUJU_DATA = os.environ.get('JUJU_DATA')
@@ -65,6 +66,9 @@ API_PORT = os.environ.get("API_PORT", 5000)
6566
66UNKNOWN_VALUE = "unknown"67UNKNOWN_VALUE = "unknown"
6768
69RETRY = 10
70SLEEP = 2
71
6872
69def get_timestamp():73def get_timestamp():
70 timestamp = time.time()74 timestamp = time.time()
@@ -87,6 +91,15 @@ def url_join(base, uri):
87 return base + uri91 return base + uri
8892
8993
94def retry(call_to_retry, num=RETRY):
95 for i in range(0, num):
96 try:
97 return call_to_retry()
98 except Exception:
99 time.sleep(SLEEP * i)
100 print("Error: failed to retrieve machines from maas [{}/{}]".format(i+1,num))
101
102
90class MaasV2(object):103class MaasV2(object):
91 def __init__(self):104 def __init__(self):
92 self.client = None105 self.client = None
@@ -117,46 +130,57 @@ class MaasV2(object):
117 else:130 else:
118 self.maas_endpoint = MAAS_ENDPOINT131 self.maas_endpoint = MAAS_ENDPOINT
119132
120 try:133 for i in range(0, RETRY):
121 if MAAS_PASSWORD:134 try:
122 self.client = login(135 if MAAS_PASSWORD:
123 self.maas_endpoint,136 self.client = login(
124 username=MAAS_USERNAME, password=MAAS_PASSWORD,137 self.maas_endpoint,
125 )138 username=MAAS_USERNAME, password=MAAS_PASSWORD,
126 elif MAAS_APIKEY:139 )
127 self.client = connect(140 elif MAAS_APIKEY:
128 self.maas_endpoint,141 self.client = connect(
129 apikey=MAAS_APIKEY142 self.maas_endpoint,
130 )143 apikey=MAAS_APIKEY
131 except Exception as e:144 )
132 print("Error connecting to MAAS endpoint: {}. {}".format(self.maas_endpoint, e))145 return self.client is not None
133146 except Exception as e:
134 return self.client is not None147 print("Error connecting to MAAS endpoint: {}. {}".format(self.maas_endpoint, e))
148 time.sleep(SLEEP * i)
135149
136 def disconnect(self):150 def disconnect(self):
137 pass151 pass
138152
139 def _list_machines(self):153 def _list_machines(self):
140 try:154 try:
141 return self.client.machines.list()155 return retry(self.client.machines.list) or []
142 except Exception as e:156 except Exception as e:
143 print("Error retrieving machines list from MAAS endpoint: {}. {}".format(self.maas_endpoint, e))157 print("Error retrieving machines list from MAAS endpoint: {}. {}".format(self.maas_endpoint, e))
144 return []158 return []
145159
146 def _list_rack_controllers(self):160 def _list_rack_controllers(self):
147 try:161 try:
148 return self.client.rack_controllers.list()162 return retry(self.client.rack_controllers.list) or []
149 except Exception as e:163 except Exception as e:
150 print("Error retrieving rack controllers list from MAAS endpoint: {}. {}".format(self.maas_endpoint, e))164 print("Error retrieving rack controllers list from MAAS endpoint: {}. {}".format(self.maas_endpoint, e))
151 return []165 return []
152166
153 def _list_region_controllers(self):167 def _list_region_controllers(self):
154 try:168 try:
155 return self.client.region_controllers.list()169 return retry(self.client.region_controllers.list) or []
156 except Exception as e:170 except Exception as e:
157 print("Error retrieving region controllers list from MAAS endpoint: {}. {}".format(self.maas_endpoint, e))171 print("Error retrieving region controllers list from MAAS endpoint: {}. {}".format(self.maas_endpoint, e))
158 return []172 return []
159173
174 def _get_maas_version(self):
175 version = "None"
176 report_version = retry(self.client.version.get)
177 if report_version:
178 version = report_version.version
179 return version
180
181 def _get_power_parameters(self, m):
182 return retry(m.get_power_parameters) or {}
183
160 def _serialize_machine(self, m):184 def _serialize_machine(self, m):
161 """185 """
162 Convert a Maas Machine into a dict.186 Convert a Maas Machine into a dict.
@@ -172,7 +196,7 @@ class MaasV2(object):
172 else:196 else:
173 status = m.status.name.lower()197 status = m.status.name.lower()
174 power_type = m.power_type.lower()198 power_type = m.power_type.lower()
175 power_address = m.get_power_parameters().get('power_address', UNKNOWN_VALUE)199 power_address = self._get_power_parameters(m).get('power_address', UNKNOWN_VALUE)
176200
177 mac_addresses = [net_if.mac_address.lower() for net_if in m.interfaces]201 mac_addresses = [net_if.mac_address.lower() for net_if in m.interfaces]
178202
@@ -198,7 +222,7 @@ class MaasV2(object):
198 :return: json report222 :return: json report
199 """223 """
200224
201 maas_version = self.client.version.get().version225 maas_version = self._get_maas_version()
202226
203 machines = list(map(self._serialize_machine, self._list_machines())) + \227 machines = list(map(self._serialize_machine, self._list_machines())) + \
204 list(map(self._serialize_machine, self._list_rack_controllers())) + \228 list(map(self._serialize_machine, self._list_rack_controllers())) + \
@@ -274,8 +298,8 @@ class MaasV1(object):
274 signature_method=oauth1.SIGNATURE_PLAINTEXT)298 signature_method=oauth1.SIGNATURE_PLAINTEXT)
275299
276 url = url_join(self.maas_endpoint, uri)300 url = url_join(self.maas_endpoint, uri)
277 uri, headers, body = client.sign(url)301 uri, headers, body = retry(client.sign(url)) or [None, None, None]
278 response = requests.get(uri, headers=headers)302 response = retry(requests.get(uri, headers=headers)) or ""
279 if response.status_code == 200:303 if response.status_code == 200:
280 return response.json()304 return response.json()
281 except Exception as e:305 except Exception as e:
@@ -374,13 +398,16 @@ class Juju(object):
374 else:398 else:
375 cmd = ['snap run juju', 'status', '--format=yaml']399 cmd = ['snap run juju', 'status', '--format=yaml']
376400
377 try:401 for i in range(0, RETRY):
378 output = subprocess.check_output(cmd, env=env)402 try:
379 parsed = yaml.safe_load(output)403 output = subprocess.check_output(cmd, timeout=30, env=env)
380 machines = parsed['machines']404 parsed = yaml.safe_load(output)
381 except subprocess.CalledProcessError as e:405 machines = parsed['machines']
382 print("Exception calling juju status command. {}".format(e))406 i = RETRY + 1
383407 except Exception as e:
408 print("Error: failed to retrieve machines from juju [{}/{}]\n{}".format(i+1,RETRY,e))
409 time.sleep(SLEEP * i)
410
384 return machines411 return machines
385412
386 def connect(self):413 def connect(self):

Subscribers

People subscribed via source and target branches

to all changes: