RIC-769: Committing individual files rather than tar archive
[ric-plt/appmgr.git] / xapp_orchestrater / dev / xapp_onboarder / xapp_onboarder / repo_manager / repo_manager.py
1 ################################################################################
2 #   Copyright (c) 2020 AT&T Intellectual Property.                             #
3 #                                                                              #
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                                    #
7 #                                                                              #
8 #       http://www.apache.org/licenses/LICENSE-2.0                             #
9 #                                                                              #
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 ################################################################################
16
17 import yaml
18 import json
19 from xapp_onboarder.server import settings
20 import logging
21 import requests
22 import time
23 from requests.adapters import HTTPAdapter
24 from requests.packages.urllib3.util.retry import Retry
25
26 log = logging.getLogger(__name__)
27
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()
30     retry = Retry(
31         total=retries,
32         read=retries,
33         connect=retries,
34         backoff_factor=backoff_factor,
35         status_forcelist=status_forcelist,
36     )
37     adapter = HTTPAdapter(max_retries=retry)
38     session.mount('http://', adapter)
39     session.mount('https://', adapter)
40     return session
41
42
43
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
49
50
51 class repoManager():
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)
56         t0 = time.time()
57         self.retry_session = requests_retry_session()
58         try:
59             response = self.retry_session.get(self.repo_url, timeout=settings.HTTP_TIME_OUT)
60         except Exception as err:
61             t1 = time.time()
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__ + ')')
64         else:
65             self.__is_repo_ready__ = True
66
67
68
69     def is_repo_ready(self):
70         return self.__is_repo_ready__
71
72     def get_index(self):
73         try:
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)
77         else:
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)
81
82     def upload_chart(self, xapp):
83
84         xapp_chart_index = self.get_index()
85         found_xapp = False
86         for chart in xapp_chart_index.get('entries', {}).get(xapp.chart_name, []):
87             if chart['version'] == xapp.chart_version:
88                 found_xapp = True
89
90         if found_xapp:
91             if settings.ALLOW_REDEPLOY:
92                 self.delete_chart(xapp)
93             else:
94                 raise RepoManagerError("Upload helm chart failed. Redeploy xApp helm chart is not allowed.", 400)
95
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()
100
101         try:
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)
105         else:
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)
108
109
110     def delete_chart(self, xapp):
111
112         headers = {'Content-Type': 'application/json'}
113
114         try:
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)
119         else:
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)
124
125
126     def get_xapp_list(self, xapp_chart_name=None):
127
128         request_path = self.repo_url+'/api/charts'
129         if xapp_chart_name:
130             request_path = request_path +'/' + xapp_chart_name
131
132         try:
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)
136         else:
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)
140
141
142     def download_xapp_chart(self, xapp_chart_name, version):
143
144         request_path = self.repo_url+'/charts/'+xapp_chart_name+'-'+version+'.tgz'
145         try:
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)
149         else:
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
153
154
155
156
157 repo_manager = repoManager(settings.CHART_REPO_URL)