1 ################################################################################
2 # Copyright (c) 2020 AT&T Intellectual Property. #
4 # Licensed under the Apache License, Version 2.0 (the "License"); #
5 # you may not use this file except in compliance with the License. #
6 # You may obtain a copy of the License at #
8 # http://www.apache.org/licenses/LICENSE-2.0 #
10 # Unless required by applicable law or agreed to in writing, software #
11 # distributed under the License is distributed on an "AS IS" BASIS, #
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13 # See the License for the specific language governing permissions and #
14 # limitations under the License. #
15 ################################################################################
19 from xapp_onboarder.server import settings
23 from requests.adapters import HTTPAdapter
24 from requests.packages.urllib3.util.retry import Retry
26 log = logging.getLogger(__name__)
28 def requests_retry_session(retries=3, backoff_factor=0.3, status_forcelist=(500, 502, 504, 400, 401, 409), session=None,):
29 session = session or requests.Session()
34 backoff_factor=backoff_factor,
35 status_forcelist=status_forcelist,
37 adapter = HTTPAdapter(max_retries=retry)
38 session.mount('http://', adapter)
39 session.mount('https://', adapter)
44 class RepoManagerError(Exception):
45 def __init__(self, message, status_code):
46 # Call the base class constructor with the parameters it needs
47 super().__init__(message)
48 self.status_code = status_code
52 def __init__(self, repo_url):
53 self.repo_url = repo_url
54 self.__is_repo_ready__ = False
55 log.debug("Initialize connection to helm chart repo at "+self.repo_url)
57 self.retry_session = requests_retry_session()
59 response = self.retry_session.get(self.repo_url, timeout=settings.HTTP_TIME_OUT)
60 except Exception as err:
62 log.error('Failed to connect to helm chart repo ' + self.repo_url + ' after ' + str(
63 settings.HTTP_RETRY) + ' retries and ' + str(t1 - t0) + ' seconds. (Caused by: ' + err.__class__.__name__ + ')')
65 self.__is_repo_ready__ = True
69 def is_repo_ready(self):
70 return self.__is_repo_ready__
74 response = self.retry_session.get(self.repo_url +'/index.yaml', timeout=settings.HTTP_TIME_OUT)
75 except Exception as err:
76 raise RepoManagerError("Get helm repo index failed. (Caused by: " + str(err)+")", 500)
78 if response.status_code != 200:
79 raise RepoManagerError("Get helm repo index failed. Helm repo return status code: {}, {}".format(response.status_code, response.content.decode("utf-8")))
80 return yaml.load(response.content, Loader=yaml.FullLoader)
82 def upload_chart(self, xapp):
84 xapp_chart_index = self.get_index()
86 for chart in xapp_chart_index.get('entries', {}).get(xapp.chart_name, []):
87 if chart['version'] == xapp.chart_version:
91 if settings.ALLOW_REDEPLOY:
92 self.delete_chart(xapp)
94 raise RepoManagerError("Upload helm chart failed. Redeploy xApp helm chart is not allowed.", 400)
96 headers = {'Content-Type': 'application/json'}
97 chart_package_path = xapp.chart_workspace_path + '/' + xapp.chart_name + '-' + xapp.chart_version + '.tgz'
98 with open(chart_package_path, mode='rb') as filereader:
99 fileContent = filereader.read()
102 response = self.retry_session.post(self.repo_url +'/api/charts', headers=headers, data=fileContent, timeout=settings.HTTP_TIME_OUT)
103 except Exception as err:
104 raise RepoManagerError("Upload helm chart failed. (Caused by: " + str(err) + ")", 500)
106 if response.status_code != 201:
107 raise RepoManagerError("Upload helm chart failed. Helm repo return status code: "+ str(response.status_code) +" "+ response.content.decode("utf-8"), response.status_code)
110 def delete_chart(self, xapp):
112 headers = {'Content-Type': 'application/json'}
115 response = self.retry_session.delete(self.repo_url +'/api/charts/' + xapp.chart_name
116 + '/' + xapp.chart_version, headers=headers, timeout=settings.HTTP_TIME_OUT)
117 except Exception as err:
118 raise RepoManagerError("Delete helm chart failed." + str(err), 500)
120 if response.status_code != 200:
121 response_dict = json.loads(response.content)
122 if xapp.chart_name+'-'+xapp.chart_version+'.tgz' not in response_dict["error"]:
123 raise RepoManagerError("Delete helm chart failed. Helm repo return status code:" + str(response.status_code) +" "+ response.content.decode("utf-8"),response.status_code)
126 def get_xapp_list(self, xapp_chart_name=None):
128 request_path = self.repo_url+'/api/charts'
130 request_path = request_path +'/' + xapp_chart_name
133 response = self.retry_session.get(request_path, timeout=settings.HTTP_TIME_OUT)
134 except Exception as err:
135 raise RepoManagerError("Get xApp charts list failed. (Caused by: " + str(err)+")", 500)
137 if response.status_code != 200:
138 raise RepoManagerError("Get xApp charts list failed. Helm repo return status code: "+ str(response.status_code) +" "+ response.content.decode("utf-8"), response.status_code)
139 return json.loads(response.content)
142 def download_xapp_chart(self, xapp_chart_name, version):
144 request_path = self.repo_url+'/charts/'+xapp_chart_name+'-'+version+'.tgz'
146 response = self.retry_session.get(request_path, timeout=settings.HTTP_TIME_OUT)
147 except Exception as err:
148 raise RepoManagerError("Download helm chart failed. (Caused by: " + str(err)+")", 500)
150 if response.status_code != 200:
151 raise RepoManagerError("Download helm chart failed. Helm repo return status code: "+ str(response.status_code) +" "+ response.content.decode("utf-8"), response.status_code)
152 return response.content
157 repo_manager = repoManager(settings.CHART_REPO_URL)