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
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'
47 def start(ds, **kwargs):
48 # Read the user input from the POST
49 yaml = read_yaml(WORKDIR + '/INPUT.yaml')
50 REC_ISO_IMAGE_NAME = yaml['iso_primary']
51 REC_PROVISIONING_ISO_NAME = yaml['iso_secondary']
52 INPUT_YAML_URL = yaml['input_yaml']
53 HOST_IP = yaml['rc_host']
54 CLOUDNAME = 'CL-'+POD.POD
55 ISO = '%s/images/install-%s.iso' % (RI_DIR, POD.POD)
56 BOOTISO = '%s/images/bootcd-%s.iso' % (RI_DIR, POD.POD)
57 USERCONF = '%s/user-configs/%s/user_config.yaml' % (RI_DIR, CLOUDNAME)
59 print('-----------------------------------------------------------------------------------------------')
60 print(' POD is '+POD.POD)
61 print(' CLOUDNAME is '+CLOUDNAME)
62 print(' WORKDIR is '+WORKDIR)
63 print(' HOST_IP is '+HOST_IP)
64 print(' EXTERNALROOT is '+EXTERNALROOT)
65 print(' REC_ISO_IMAGE_NAME is '+REC_ISO_IMAGE_NAME)
66 print('REC_PROVISIONING_ISO_NAME is '+REC_PROVISIONING_ISO_NAME)
67 print(' INPUT_YAML_URL is '+INPUT_YAML_URL)
69 print(' BOOTISO is '+BOOTISO)
70 print(' USERCONF is '+USERCONF)
71 print('-----------------------------------------------------------------------------------------------')
74 initialize_RI(CLOUDNAME)
76 # Fetch the three files into WORKDIR
77 fetchURL(REC_ISO_IMAGE_NAME, WORKDIR + '/install.iso');
78 fetchURL(REC_PROVISIONING_ISO_NAME, WORKDIR + '/bootcd.iso');
79 fetchURL(INPUT_YAML_URL, WORKDIR + '/user_config.yaml');
81 # Link files to RI_DIR with unique names
82 os.link(WORKDIR + '/install.iso', ISO)
83 os.link(WORKDIR + '/bootcd.iso', BOOTISO)
84 os.link(WORKDIR + '/user_config.yaml', USERCONF)
85 PWFILE = '%s/user-configs/%s/admin_passwd' % (RI_DIR, CLOUDNAME)
86 with open(PWFILE, "w") as f:
87 f.write(ADMIN_PASSWD + '\n')
89 # Start the remote_installer
90 client = docker.from_env()
91 namefilt = { 'name': RI_NAME }
92 ri = client.containers.list(filters=namefilt)
94 print(RI_NAME + ' is not running.')
98 print(RI_NAME + ' is running.')
101 # Send request to remote_installer
102 id = send_request(HOST_IP, CLOUDNAME, ISO, BOOTISO)
104 # Wait up to WAIT_TIME minutes for completion
105 if wait_for_completion(HOST_IP, id, WAIT_TIME):
106 print('Installation failed after %d minutes.' % (WAIT_TIME))
111 for iso in (WORKDIR + '/install.iso', ISO, WORKDIR + '/bootcd.iso', BOOTISO):
115 print('Installation complete!')
116 # sys.exit(0) Don't exit as this will cause the task to fail!
119 def read_yaml(input_file):
120 print('Reading '+input_file+' ...')
121 with open(input_file, 'r') as stream:
123 return yaml.safe_load(stream)
124 except yaml.YAMLError as exc:
128 def send_request(ri_ip, CLOUDNAME, ISO, BOOTISO):
129 URL = 'https://%s:%d/v1/installations' % (ri_ip, API_PORT)
130 print('Sending request to '+URL+' ...')
131 headers = {'Content-type': 'application/json'}
133 'cloud-name': CLOUDNAME,
134 'iso': os.path.basename(ISO),
135 'provisioning-iso': os.path.basename(BOOTISO)
137 certs = (CERT_DIR+'/clientcert.pem', CERT_DIR+'/clientkey.pem')
138 response = requests.post(URL, json=content, headers=headers, cert=certs, verify=False)
140 return response.json().get('uuid')
142 def wait_for_completion(ri_ip, id, ntimes):
144 Wait (up to ntimes minutes) for the remote_installer to finish.
145 Any status other than 'completed' is considered a failure.
148 URL = 'https://%s:%d/v1/installations/%s/state' % (ri_ip, API_PORT, id)
149 certs = (CERT_DIR+'/clientcert.pem', CERT_DIR+'/clientkey.pem')
150 while status == 'ongoing' and ntimes > 0:
152 response = requests.get(URL, cert=certs, verify=False)
155 datetime.datetime.now().strftime('%x %X'),
156 str(j.get('status')),
157 str(j.get('percentage')),
158 str(j.get('description'))
160 print('%s: Status is %s (%s) %s' % t)
161 status = j.get('status')
163 return status != 'completed'
165 def fetchURL(url, dest):
166 print('Fetching '+url+' ...')
167 r = requests.get(url)
168 with open(dest, 'wb') as f1:
171 def initialize_RI(CLOUDNAME):
172 """ Create the directory structure needed by the remote-installer """
175 RI_DIR+'/certificates',
177 RI_DIR+'/installations',
178 RI_DIR+'/user-configs',
179 RI_DIR+'/user-configs/'+CLOUDNAME
182 if not os.path.isdir(dir):
186 def start_RI(client):
188 Start the remote-installer container (assumed to already be built somewhere).
189 Before starting, make sure the certificates directory is populated. If not,
190 generate some self-signed certificates.
192 # If needed, create certificates (11 files) in RI_DIR/certificates
193 if not os.path.exists(CERT_DIR+'/clientcert.pem') or not os.path.exists(CERT_DIR+'/clientkey.pem'):
194 print('Generating some self-signed certificates.')
195 script = WORKDIR + '/gencerts.sh'
196 cmd = 'bash %s %s' % (script, RI_DIR+'/certificates')
197 print('os.system('+cmd+')')
200 print('Starting %s.' % RI_NAME)
202 'API_PORT': API_PORT, 'HOST_ADDR': HOST_IP, 'HTTPS_PORT': HTTPS_PORT,
203 'PW': ADMIN_PASSWD, 'SSH_PORT': 22222
206 EXTERNALROOT+RI_DIR: {'bind': '/opt/remoteinstaller', 'mode': 'rw'}
209 c = client.containers.run(
212 network_mode=NETWORK,
220 # Wait 5 minutes for it to be running
222 while c.status != 'running' and n < 10:
226 if c.status != 'running' and n >= 10:
227 print('Container took to long to start!')
231 except docker.errors.ImageNotFound as ex:
232 # If the specified image does not exist.
236 except docker.errors.APIError as ex:
237 # If the server returns an error.
242 print('other error!')