3 # Copyright (c) 2019 AT&T Intellectual Property. All Rights Reserved.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
19 REC_create.py - This workflow is used to create a REC POD by way of the remote-installer
20 container. The remote-installer is started if it is not running. Parameters passed to
21 this script (via the INPUT.yaml file) are:
22 iso_primary - the main installer.iso file to use
23 iso_secondary - the secondary bootcd.iso file
24 input_yaml - the YAML file passed to remote_installer
25 rc_host - the IP address or DNS name of the RC
30 import requests, urllib3
31 import os, sys, time, yaml
34 WORKDIR = os.path.abspath(os.path.dirname(__file__))
35 RI_NAME = 'remote-installer'
36 RI_IMAGE = 'nexus3.akraino.org:10003/akraino/remote-installer:latest'
37 RI_DIR = '/workflow/remote-installer'
38 CERT_DIR = RI_DIR + '/certificates'
39 EXTERNALROOT = '/data'
44 ADMIN_PASSWD = 'recAdm1n'
48 def start(ds, **kwargs):
49 # Read the user input from the POST
51 urllib3.disable_warnings()
52 yaml = read_yaml(WORKDIR + '/INPUT.yaml')
53 REC_ISO_IMAGE_NAME = yaml['iso_primary']
54 REC_PROVISIONING_ISO_NAME = yaml['iso_secondary']
55 INPUT_YAML_URL = yaml['input_yaml']
56 HOST_IP = yaml['rc_host']
57 CLOUDNAME = 'CL-'+POD.POD
58 ISO = '%s/images/install-%s.iso' % (RI_DIR, POD.POD)
59 BOOTISO = '%s/images/bootcd-%s.iso' % (RI_DIR, POD.POD)
60 USERCONF = '%s/user-configs/%s/user_config.yaml' % (RI_DIR, CLOUDNAME)
62 print('-----------------------------------------------------------------------------------------------')
63 print(' POD is '+POD.POD)
64 print(' CLOUDNAME is '+CLOUDNAME)
65 print(' WORKDIR is '+WORKDIR)
66 print(' HOST_IP is '+HOST_IP)
67 print(' EXTERNALROOT is '+EXTERNALROOT)
68 print(' REC_ISO_IMAGE_NAME is '+REC_ISO_IMAGE_NAME)
69 print('REC_PROVISIONING_ISO_NAME is '+REC_PROVISIONING_ISO_NAME)
70 print(' INPUT_YAML_URL is '+INPUT_YAML_URL)
72 print(' BOOTISO is '+BOOTISO)
73 print(' USERCONF is '+USERCONF)
74 print('-----------------------------------------------------------------------------------------------')
77 initialize_RI(CLOUDNAME)
79 # Fetch the three files into WORKDIR
80 fetchURL(REC_ISO_IMAGE_NAME, WORKDIR + '/install.iso');
81 fetchURL(REC_PROVISIONING_ISO_NAME, WORKDIR + '/bootcd.iso');
82 fetchURL(INPUT_YAML_URL, WORKDIR + '/user_config.yaml');
84 # Link files to RI_DIR with unique names
85 os.link(WORKDIR + '/install.iso', ISO)
86 os.link(WORKDIR + '/bootcd.iso', BOOTISO)
87 os.link(WORKDIR + '/user_config.yaml', USERCONF)
88 PWFILE = '%s/user-configs/%s/admin_passwd' % (RI_DIR, CLOUDNAME)
89 with open(PWFILE, "w") as f:
90 f.write(ADMIN_PASSWD + '\n')
92 # Start the remote_installer
93 client = docker.from_env()
94 namefilt = { 'name': RI_NAME }
95 ri = client.containers.list(filters=namefilt)
97 print(RI_NAME + ' is not running.')
101 print(RI_NAME + ' is running.')
104 # Send request to remote_installer
105 id = send_request(HOST_IP, CLOUDNAME, ISO, BOOTISO)
107 # Wait up to WAIT_TIME minutes for completion
108 if wait_for_completion(HOST_IP, id, WAIT_TIME):
109 print('Installation failed after %d minutes.' % (WAIT_TIME))
114 for iso in (WORKDIR + '/install.iso', ISO, WORKDIR + '/bootcd.iso', BOOTISO):
118 print('Installation complete!')
119 # sys.exit(0) Don't exit as this will cause the task to fail!
122 def read_yaml(input_file):
123 print('Reading '+input_file+' ...')
124 with open(input_file, 'r') as stream:
126 return yaml.safe_load(stream)
127 except yaml.YAMLError as exc:
131 def send_request(ri_ip, CLOUDNAME, ISO, BOOTISO):
132 URL = 'https://%s:%d/v1/installations' % (ri_ip, API_PORT)
133 print('Sending request to '+URL+' ...')
134 headers = {'Content-type': 'application/json'}
136 'cloud-name': CLOUDNAME,
137 'iso': os.path.basename(ISO),
138 'provisioning-iso': os.path.basename(BOOTISO)
140 certs = (CERT_DIR+'/clientcert.pem', CERT_DIR+'/clientkey.pem')
141 response = requests.post(URL, json=content, headers=headers, cert=certs, verify=False)
143 return response.json().get('uuid')
145 def wait_for_completion(ri_ip, id, ntimes):
147 Wait (up to ntimes minutes) for the remote_installer to finish.
148 Any status other than 'completed' is considered a failure.
151 URL = 'https://%s:%d/v1/installations/%s/state' % (ri_ip, API_PORT, id)
152 certs = (CERT_DIR+'/clientcert.pem', CERT_DIR+'/clientkey.pem')
153 while status == 'ongoing' and ntimes > 0:
155 response = requests.get(URL, cert=certs, verify=False)
158 datetime.datetime.now().strftime('%x %X'),
159 str(j.get('status')),
160 str(j.get('percentage')),
161 str(j.get('description'))
163 print('%s: Status is %s (%s) %s' % t)
164 status = j.get('status')
166 return status != 'completed'
168 def fetchURL(url, dest):
169 print('Fetching '+url+' ...')
170 r = requests.get(url)
171 with open(dest, 'wb') as f1:
174 def initialize_RI(CLOUDNAME):
175 """ Create the directory structure needed by the remote-installer """
178 RI_DIR+'/certificates',
180 RI_DIR+'/installations',
181 RI_DIR+'/user-configs',
182 RI_DIR+'/user-configs/'+CLOUDNAME
185 if not os.path.isdir(dir):
189 def start_RI(client):
191 Start the remote-installer container (assumed to already be built somewhere).
192 Before starting, make sure the certificates directory is populated. If not,
193 generate some self-signed certificates.
195 # If needed, create certificates (11 files) in RI_DIR/certificates
196 if not os.path.exists(CERT_DIR+'/clientcert.pem') or not os.path.exists(CERT_DIR+'/clientkey.pem'):
197 print('Generating some self-signed certificates.')
198 script = WORKDIR + '/gencerts.sh'
199 cmd = 'bash %s %s' % (script, RI_DIR+'/certificates')
200 print('os.system('+cmd+')')
203 print('Starting %s.' % RI_NAME)
205 'API_PORT': API_PORT, 'HOST_ADDR': HOST_IP, 'HTTPS_PORT': HTTPS_PORT,
206 'PW': ADMIN_PASSWD, 'SSH_PORT': 22222
209 EXTERNALROOT+RI_DIR: {'bind': '/opt/remoteinstaller', 'mode': 'rw'}
212 c = client.containers.run(
215 network_mode=NETWORK,
223 # Wait 5 minutes for it to be running
225 while c.status != 'running' and n < 10:
229 if c.status != 'running' and n >= 10:
230 print('Container took to long to start!')
234 except docker.errors.ImageNotFound as ex:
235 # If the specified image does not exist.
239 except docker.errors.APIError as ex:
240 # If the server returns an error.
245 print('other error!')