1 # ============LICENSE_START=======================================================
2 # Copyright (C) 2019 Nordix Foundation.
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
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.
16 # SPDX-License-Identifier: Apache-2.0
17 # ============LICENSE_END=========================================================
32 log_file = '/opt/opendaylight/data/log/installCerts.log'
33 with open(os.path.join('/opt/opendaylight/data/log', 'installCerts.log'), 'w') as fp:
36 log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
37 logging.basicConfig(filename=log_file,level=logging.DEBUG,filemode='w',format=log_format)
43 username = os.environ['ODL_ADMIN_USERNAME']
44 password = os.environ['ODL_ADMIN_PASSWORD']
49 postKeystore= "/restconf/operations/netconf-keystore:add-keystore-entry"
50 postPrivateKey= "/restconf/operations/netconf-keystore:add-private-key"
51 postTrustedCertificate= "/restconf/operations/netconf-keystore:add-trusted-certificate"
53 truststore_pass_file = Path + '/truststore.pass'
54 truststore_file = Path + '/truststore.jks'
56 keystore_pass_file = Path + '/keystore.pass'
57 keystore_file = Path + '/keystore.jks'
59 jks_files = [truststore_pass_file, keystore_pass_file, keystore_file, truststore_file]
62 headers = {'Authorization':'Basic %s' % base64.b64encode(username + ":" + password),
63 'X-FromAppId': 'csit-sdnc',
64 'X-TransactionId': 'csit-sdnc',
65 'Accept':"application/json",
66 'Content-type':"application/json"}
69 def readFile(folder, file):
70 key = open(Path + "/" + folder + "/" + file, "r")
73 fileRead = "\n".join(fileRead.splitlines()[1:-1])
77 def readTrustedCertificate(folder, file):
81 key = open(folder + "/" + file, "r")
82 lines = key.readlines()
84 if not "BEGIN CERTIFICATE" in line and not "END CERTIFICATE" in line and startCa:
86 elif "BEGIN CERTIFICATE" in line:
88 elif "END CERTIFICATE" in line:
90 listCert.append(caPem)
95 def makeKeystoreKey(clientKey, count):
96 odl_private_key = "ODL_private_key_%d" %count
98 json_keystore_key='{{\"input\": {{ \"key-credential\": {{\"key-id\": \"{odl_private_key}\", \"private-key\" : ' \
99 '\"{clientKey}\",\"passphrase\" : \"\"}}}}}}'.format(
100 odl_private_key=odl_private_key,
103 return json_keystore_key
106 def makePrivateKey(clientKey, clientCrt, certList, count):
109 for cert in certList:
110 caPem += '\"%s\",' % cert
111 caPem = caPem.rsplit(',', 1)[0]
112 odl_private_key="ODL_private_key_%d" %count
114 json_private_key='{{\"input\": {{ \"private-key\":{{\"name\": \"{odl_private_key}\", \"data\" : ' \
115 '\"{clientKey}\",\"certificate-chain\":[\"{clientCrt}\",{caPem}]}}}}}}'.format(
116 odl_private_key=odl_private_key,
121 return json_private_key
124 def makeTrustedCertificate(certList, count):
126 json_cert_format = ""
127 for cert in certList:
128 cert_name = "xNF_CA_certificate_%d_%d" %(count, number)
129 json_cert_format += '{{\"name\": \"{trusted_name}\",\"certificate\":\"{cert}\"}},\n'.format(
130 trusted_name=cert_name,
134 json_cert_format = json_cert_format.rsplit(',', 1)[0]
135 json_trusted_cert='{{\"input\": {{ \"trusted-certificate\": [{certificates}]}}}}'.format(
136 certificates=json_cert_format)
137 return json_trusted_cert
140 def makeRestconfPost(conn, json_file, apiCall):
141 req = conn.request("POST", apiCall, json_file, headers=headers)
142 res = conn.getresponse()
144 if res.status != 200:
145 logging.error("Error here, response back wasnt 200: Response was : %d , %s" % (res.status, res.reason))
147 logging.debug("Response :%s Reason :%s ",res.status, res.reason)
150 def extractZipFiles(zipFileList, count):
151 for zipFolder in zipFileList:
152 with zipfile.ZipFile(Path + "/" + zipFolder.strip(),"r") as zip_ref:
153 zip_ref.extractall(Path)
154 folder = zipFolder.rsplit(".")[0]
155 processFiles(folder, count)
158 def processFiles(folder, count):
159 for file in os.listdir(Path + "/" + folder):
160 if os.path.isfile(Path + "/" + folder + "/" + file.strip()):
162 clientKey = readFile(folder, file.strip())
163 elif "trustedCertificate" in file:
164 certList = readTrustedCertificate(Path + "/" + folder, file.strip())
166 clientCrt = readFile(folder, file.strip())
168 logging.error("Could not find file %s" % file.strip())
169 shutil.rmtree(Path + "/" + folder)
170 post_content(clientKey, clientCrt, certList, count)
173 def post_content(clientKey, clientCrt, certList, count):
174 conn = httplib.HTTPConnection("localhost",odl_port)
177 json_keystore_key = makeKeystoreKey(clientKey, count)
178 logging.debug("Posting private key in to ODL keystore")
179 makeRestconfPost(conn, json_keystore_key, postKeystore)
182 json_trusted_cert = makeTrustedCertificate(certList, count)
183 logging.debug("Posting trusted cert list in to ODL")
184 makeRestconfPost(conn, json_trusted_cert, postTrustedCertificate)
186 if clientKey and clientCrt and certList:
187 json_private_key = makePrivateKey(clientKey, clientCrt, certList, count)
188 logging.debug("Posting the cert in to ODL")
189 makeRestconfPost(conn, json_private_key, postPrivateKey)
192 def makeHealthcheckCall(headers, timePassed):
194 # WAIT 10 minutes maximum and test every 30 seconds if HealthCheck API is returning 200
195 while timePassed < TIMEOUT:
197 conn = httplib.HTTPConnection("localhost",odl_port)
198 req = conn.request("POST", "/restconf/operations/SLI-API:healthcheck",headers=headers)
199 res = conn.getresponse()
201 if res.status == 200:
202 logging.debug("Healthcheck Passed in %d seconds." %timePassed)
206 logging.debug("Sleep: %d seconds before testing if Healthcheck worked. Total wait time up now is: %d seconds. Timeout is: %d seconds" %(INTERVAL, timePassed, TIMEOUT))
208 logging.error("Cannot execute REST call. Sleep: %d seconds before testing if Healthcheck worked. Total wait time up now is: %d seconds. Timeout is: %d seconds" %(INTERVAL, timePassed, TIMEOUT))
209 timePassed = timeIncrement(timePassed)
211 if timePassed > TIMEOUT:
212 logging.error("TIME OUT: Healthcheck not passed in %d seconds... Could cause problems for testing activities..." %TIMEOUT)
216 def timeIncrement(timePassed):
218 timePassed = timePassed + INTERVAL
222 def get_pass(file_name):
224 with open(file_name, 'r') as file_obj:
225 password = file_obj.read().strip()
226 return "'{}'".format(password)
227 except Exception as e:
228 logging.error("Error occurred while fetching password : %s", e)
233 for file in jks_files:
234 if os.path.isfile(file):
235 logging.debug("Cleaning up the file %s", file)
239 def jks_to_p12(file, password):
240 """Converts jks format into p12"""
242 p12_file = file.replace('.jks', '.p12')
243 jks_cmd = 'keytool -importkeystore -srckeystore {src_file} -destkeystore {dest_file} -srcstoretype JKS -srcstorepass {src_pass} -deststoretype PKCS12 -deststorepass {dest_pass}'.format(src_file=file, dest_file=p12_file, src_pass=password, dest_pass=password)
244 logging.debug("Converting %s into p12 format", file)
248 except Exception as e:
249 logging.error("Error occurred while converting jks to p12 format : %s", e)
252 def extract_content():
253 """Extracts client key, certificates, CA certificates."""
259 truststore_pass = get_pass(truststore_pass_file)
260 truststore_file_p12 = jks_to_p12(truststore_file, truststore_pass)
262 keystore_pass = get_pass(keystore_pass_file)
263 keystore_file_p12 = jks_to_p12(keystore_file, keystore_pass)
265 clcrt_cmd = 'openssl pkcs12 -in {src_file} -clcerts -nokeys -passin pass:{src_pass}'.format(src_file=keystore_file_p12, src_pass=keystore_pass)
267 clkey_cmd = 'openssl pkcs12 -in {src_file} -nocerts -nodes -passin pass:{src_pass}'.format(src_file=keystore_file_p12, src_pass=keystore_pass)
268 trust_file = truststore_file_p12.split('/')[2] + '.trust'
270 trustCerts_cmd = 'openssl pkcs12 -in {src_file} -out {out_file} -cacerts -nokeys -passin pass:{src_pass} '.format(src_file=truststore_file_p12, out_file=Path + '/' + trust_file, src_pass=truststore_pass)
272 result_key = subprocess.check_output(clkey_cmd , shell=True)
274 key = result_key.split('-----BEGIN PRIVATE KEY-----', 1)[1].lstrip().split('-----END PRIVATE KEY-----')[0]
275 logging.debug("key ok")
277 os.system(trustCerts_cmd)
278 if os.path.exists(Path + '/' + trust_file):
279 certList = readTrustedCertificate(Path, trust_file)
280 logging.debug("certList ok")
282 result_crt = subprocess.check_output(clcrt_cmd , shell=True)
284 cert = result_crt.split('-----BEGIN CERTIFICATE-----', 1)[1].lstrip().split('-----END CERTIFICATE-----')[0]
285 logging.debug("cert ok")
287 if key and cert and certList:
288 post_content(key, cert, certList, 0)
290 logging.debug("Exiting. Key, cert or key are missing")
293 except Exception as e:
294 logging.error("Error occurred while processing the file: %s", e)
297 def look_for_jks_files():
298 if all([os.path.isfile(f) for f in jks_files]):
302 logging.debug("Some of the files are missing")
306 def readCertProperties():
308 This function searches for manually copied zip file
309 containing certificates. This is required as part
310 of backward compatibility.
311 If not foud, it searches for jks certificates.
313 connected = makeHealthcheckCall(headers, timePassed)
317 if os.path.isfile(Path + "/certs.properties"):
318 with open(Path + "/certs.properties", "r") as f:
320 if not "*****" in line:
321 zipFileList.append(line)
323 extractZipFiles(zipFileList, count)
327 logging.debug("No zipfiles present in folder " + Path)
329 logging.info("Looking for jks files in folder " + Path)