def file_download(client, params, user_data): """ Callback for the "file_download" method which downloads a file from the cloud to the local system. """ file_name = None file_path = None result = None timeout = 15 blocking = user_data[1] if hasattr(config, "download_timeout"): timeout = config.download_timeout if params: file_name = params.get("file_name") file_path = params.get("file_path") if file_name and not file_path: file_path = abspath( os.path.join(user_data[0], "download", file_name)) if file_path and not file_name: file_name = os.path.basename(file_path) if file_path.startswith('~'): result = iot.STATUS_BAD_PARAMETER message = "Paths cannot use '~' to reference a home directory" elif not os.path.isabs(file_path): file_path = abspath( os.path.join(user_data[0], "download", file_path)) file_global = params.get("use_global_store", False) if result is None: if file_name and file_path: dir_path = os.path.dirname(file_path) if not os.path.exists(dir_path): try: os.makedirs(dir_path) except (OSError, IOError) as e: result = iot.STATUS_IO_ERROR message = ( "Destination directory does not exist and could " "not be created!") client.error(message) print(e) if result is None: client.log(iot.LOGINFO, "Downloading") result = client.file_download(file_name, file_path, \ blocking=blocking, timeout=timeout, \ file_global=file_global) if result == iot.STATUS_SUCCESS: message = "" else: message = iot.status_string(result) else: result = iot.STATUS_BAD_PARAMETER message = "No file name or destination given" return (result, message)
def file_upload(client, params, user_data): """ Callback for the "file_upload" method which uploads a file from the cloud to the local system. Wildcards in the file name are supported. """ file_name = None file_path = None result = None if params: file_name = params.get("file_name") file_path = params.get("file_path") if file_name and not file_path: file_path = abspath(os.path.join(user_data[0], "upload", file_name)) if file_path and not file_name: file_name = os.path.basename(file_path) if file_path.startswith('~'): result = iot.STATUS_BAD_PARAMETER message = "Paths cannot use '~' to reference a home directory" elif not os.path.isabs(file_path): file_path = abspath(os.path.join(user_data[0], "upload", file_path)) file_global = params.get("use_global_store", False) if result is None: if file_name and file_path: client.log(iot.LOGINFO, "Uploading {}".format(file_name)) result = client.file_upload(file_path, upload_name=file_name, \ blocking=True, timeout=240, \ file_global=file_global) if result == iot.STATUS_SUCCESS: message = "" if user_data[1] and file_path.startswith(user_data[0]): os.remove(file_name) else: message = iot.status_string(result) else: result = iot.STATUS_BAD_PARAMETER message = "No file name or location given" return (result, message)
def file_upload(client, params, user_data): """ Callback for the "file_upload" method which uploads a file from the cloud to the local system. Wildcards in the file name are supported. """ file_name = None if params: file_name = params.get("file_name") if "dest_name" in params: dest_name = params.get("dest_name") else: dest_name = None file_global = params.get("global", False) if file_name: if not file_name.startswith('~'): if not file_name.startswith('/'): file_name = abspath(os.path.join(user_data[0], "upload", \ file_name)) client.log(iot.LOGINFO, "Uploading {}".format(file_name)) result = client.file_upload(file_name, upload_name=dest_name, \ blocking=True, timeout=240, \ file_global=file_global) if result == iot.STATUS_SUCCESS: message = "" else: message = iot.status_string(result) else: message = "Paths cannot use '~' to reference a home directory" result = iot.STATUS_BAD_PARAMETER else: result = iot.STATUS_BAD_PARAMETER message = "No file name given" return (result, message)
def file_upload(client, params, user_data): """ Callback for the "file_upload" method which uploads a file from the cloud to the local system. Wildcards in the file name are supported. """ file_name = None file_path = None result = None tarfile_name = None # config parameters that are passed up runtime_dir = user_data[0] rm_on_success = user_data[1] upload_format_is_tar = user_data[2] blocking = user_data[3] if params: file_name = params.get("file_name") file_path = params.get("file_path") if file_name and not file_path: file_path = abspath(os.path.join(runtime_dir, "upload", file_name)) if file_path and not file_name: file_name = os.path.basename(file_path) if file_path and os.path.isdir(file_path): file_path, file_name = file_upload_dir(user_data, file_path, file_name) # when uploading a dir, we tar it off first. Track the # name so that we can delete it. tarfile_name = file_path if not file_name and not file_path: file_path, file_name = file_upload_dir(user_data, file_path, file_name) # when uploading a dir, we tar it off first. Track the # name so that we can delete it. tarfile_name = file_path if file_path.startswith('~'): result = iot.STATUS_BAD_PARAMETER message = "Paths cannot use '~' to reference a home directory" elif not os.path.isabs(file_path): file_path = abspath(os.path.join(runtime_dir, "upload", file_path)) file_global = params.get("use_global_store", False) if result is None: if file_name and file_path: client.log(iot.LOGINFO, "Uploading {}".format(file_name)) result = client.file_upload(file_path, upload_name=file_name, \ blocking=blocking, timeout=240, \ file_global=file_global) if result == iot.STATUS_SUCCESS: message = "" # If upload_tar_file, delete tar file that was created if tarfile_name and blocking: os.remove(tarfile_name) # Clean up files. If the file_path has /upload/ in # it, clean up if requested if os.sep + "upload" + os.sep in file_path: try: # If upload_tar_file, delete associated files if upload_format_is_tar: base = os.path.dirname(file_path) for fn in os.listdir(base): if rm_on_success: os.remove(base + os.sep + fn) # If all of runtime_dir/upload uploaded, delete all files elif file_name == "upload": for fn in os.listdir(file_path): if rm_on_success: os.remove(file_path + os.sep + fn) else: if rm_on_success: os.remove(file_path) except (OSError, IOError) as err: error = str(err) print(error + ". Unable to remove file.") else: message = iot.status_string(result) else: result = iot.STATUS_BAD_PARAMETER message = "No file name or location given" return (result, message)
def _update_software(self, client, params, request): """ Main method that will run in a new thread and perform all the software updates """ status = iot.STATUS_BAD_PARAMETER update_data = None package_name = None override_ota_logfile_name = None client.log(iot.LOGINFO, "Started OTA Update") client.event_publish("OTA: Started OTA Update") client.action_progress_update(request.request_id, "Started OTA Update") package_dir = os.path.join(self._runtime_dir, OTA_PACKAGEDIR) # Cleanup last ota artifacts if os.path.isdir(package_dir): client.log(iot.LOGINFO, "Clean up previous update artifacts...") shutil.rmtree(package_dir) # get extra params extra_params = params.get("extra_params") client.log(iot.LOGINFO, "Extra parameters {}".format(extra_params)) if params: error_notified = False download_timeout = params.get("ota_timeout") if params.get("ota_logfile"): override_ota_logfile_name = self._scrub_file_name( client, params.get("ota_logfile")) client.log( iot.LOGINFO, "Override OTA logfile name {}".format( override_ota_logfile_name)) # 1. Download Package client.log(iot.LOGINFO, "Downloading Package...") client.event_publish("OTA: Downloading Package...") package_name = params.get("package") client.alarm_publish(ALARM_NAME, ALARM_STARTED, message="package: {}".format(package_name)) status = self._package_download(client, package_name, download_timeout) # 2. Unzip Package if status == iot.STATUS_SUCCESS or self.offline: client.log(iot.LOGINFO, "Download Phase Done!") client.event_publish("OTA: Download Successful!") client.log(iot.LOGINFO, "Unzipping Package...") client.event_publish("OTA: Unzipping Package...") status = self._package_unzip(package_name, package_dir) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Download Failed!") client.event_publish("OTA: Download Failed!") # 3. Read Update Data from JSON File if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Unzip Complete!") client.event_publish("OTA: Package Unzip Successful!") client.log(iot.LOGINFO, "Reading Update Data...") client.event_publish("OTA: Reading Update Data...") status, update_data = self._read_update_json(package_dir) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Unzip Failed!") client.event_publish("OTA: Package Unzip Failed!") # 4. Run Pre-Install if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Data Read Successful!") client.event_publish("OTA: Update Data Read Successfully!") client.log(iot.LOGINFO, "Running Pre-Install...") client.event_publish("OTA: Running Pre-Install...") client.action_progress_update(request.request_id, "Running Pre-Install") client.alarm_publish( ALARM_NAME, ALARM_PRE_INSTALL, message="package: {}".format(package_name)) if not update_data.get('pre_install', ""): status = iot.STATUS_SUCCESS client.log(iot.LOGINFO, "No Pre-Install specified! " "Continuing.") client.event_publish("OTA: No Pre-Install specified! " "Continuing.") else: status = self._execute(update_data['pre_install'], \ package_dir, extra_params) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Data Read Failed!") client.event_publish("OTA: Failed to Read Update Data!") # 5. Run Install if status == iot.STATUS_SUCCESS: if update_data.get('pre_install', ""): client.log(iot.LOGINFO, "Pre-Install Complete!") client.event_publish("OTA: Pre-Install Successful!") client.action_progress_update(request.request_id, "Pre-Install Successful") client.log(iot.LOGINFO, "Running Install...") client.event_publish("OTA: Running Install...") client.action_progress_update(request.request_id, "Running Install") client.alarm_publish( ALARM_NAME, ALARM_INSTALL, message="package: {}".format(package_name)) status = self._execute(update_data['install'], package_dir, extra_params) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Pre-Install Failed!") client.event_publish("OTA: Pre-Install Failed!") client.action_progress_update(request.request_id, "Pre-Install Failed") # 6. Run Post-Install if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Install Complete!") client.event_publish("OTA: Install Successful!") client.action_progress_update(request.request_id, "Install Successful") client.log(iot.LOGINFO, "Running Post-Install...") client.event_publish("OTA: Running Post-Install...") client.action_progress_update(request.request_id, "Running Post-Install") client.alarm_publish( ALARM_NAME, ALARM_POST_INSTALL, message="package: {}".format(package_name)) if not update_data.get('post_install', ""): status = iot.STATUS_SUCCESS client.log(iot.LOGINFO, "No Post-Install specified! " "Continuing.") client.event_publish("OTA: No Post-Install specified! " "Continuing.") else: status = self._execute(update_data['post_install'], \ package_dir, extra_params) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Install Failed!") client.event_publish("OTA: Install Failed!") client.action_progress_update(request.request_id, "Install Failed") if status == iot.STATUS_SUCCESS: if update_data.get('post_install', ""): client.log(iot.LOGINFO, "Post-Install Complete!") client.event_publish("OTA: Post-Install Successful!") client.action_progress_update(request.request_id, "Post-Install Successful") status = iot.STATUS_SUCCESS elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Post-Install Failed!") client.event_publish("OTA: Post-Install Failed!") client.action_progress_update(request.request_id, "Post-Install Failed") # 7. Report Final Status if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "OTA Successful!") client.event_publish("OTA: Update Successful!") client.action_progress_update(request.request_id, "Update Successful") client.alarm_publish(ALARM_NAME, ALARM_COMPLETE, message="package: {}".format(package_name)) status_string = "" else: if update_data and 'error_action' in update_data and \ update_data['error_action']: client.event_publish("OTA: Running install error action!") client.alarm_publish( ALARM_NAME, ALARM_INSTALL_ERROR, message="package: {}".format(package_name)) client.log(iot.LOGWARNING, "Running install error action!") self._execute(update_data['error_action'], package_dir, extra_params) client.log(iot.LOGERROR, "OTA Failed!") client.event_publish("OTA: Update Failed!") client.action_progress_update(request.request_id, "Update Failed") client.alarm_publish(ALARM_NAME, ALARM_FAILED, message="package: {}".format(package_name)) status_string = iot.status_string(status) # ----------------------------------------------------------------- # write the id,status to a file for when the agent is updated. The # device manager checks for a file "message_ids" and acks the # action. # ----------------------------------------------------------------- path = os.path.join(self._runtime_dir, "message_ids") open_mode = 'w' if os.path.exists(path): open_mode = 'a' with open(path, open_mode) as fh: fh.write("{},{}\n".format(request.request_id, status)) client.action_acknowledge(request.request_id, status, status_string) file_name = os.path.join(self._runtime_dir, "download", package_name) if os.path.isfile(file_name): client.log(iot.LOGWARNING, "removing file name %s" % file_name) os.remove(file_name) # Unlock the updater try: os.remove(os.path.join(self._runtime_dir, OTA_LOCKFILE)) except (OSError, IOError) as err: error = str(err) print( error + ". This file will block future OTA operations. Please remove it." ) client.log(iot.LOGINFO, \ "Update finished with status {}".format(iot.status_string(status))) stdout_log = os.path.abspath(os.path.join(package_dir, OTA_STDOUT_LOG)) client.log(iot.LOGINFO, "Logging stdout to file {}".format(stdout_log)) # print the stdout log to the client log # upload the stdout log to cloud if os.path.isfile(stdout_log): client.log(iot.LOGINFO, "OTA STDOUT log dump start") with open(stdout_log) as fh: while True: line = fh.readline() if line == "": break else: client.log(iot.LOGINFO, "{}".format(line.rstrip())) client.log(iot.LOGINFO, "OTA STDOUT log dump complete.") ts = datetime.utcnow().strftime("%Y-%m-%d-%S") client.log( iot.LOGINFO, "override_ota_logfile_name {} \n\n".format( override_ota_logfile_name)) if override_ota_logfile_name is not '': output_file = override_ota_logfile_name else: output_file = "ota_install-{}.log".format(ts) client.file_upload(stdout_log, upload_name=output_file, blocking=True, timeout=60, file_global=False), # Reboot if requested if update_data and 'reboot' in update_data and \ update_data['reboot'] == 'yes': osal.system_reboot()
def _update_software(self, client, params, request): """ Main method that will run in a new thread and perform all the software updates """ status = iot.STATUS_BAD_PARAMETER update_data = None client.alarm_publish(ALARM_NAME, ALARM_STARTED) client.log(iot.LOGINFO, "Started OTA Update") client.event_publish("OTA: Started OTA Update") client.action_progress_update(request.request_id, "Started OTA Update") package_dir = os.path.join(self._runtime_dir, OTA_PACKAGEDIR) if params: error_notified = False download_timeout = params.get("ota_timeout") # 1. Download Package client.log(iot.LOGINFO, "Downloading Package...") client.event_publish("OTA: Downloading Package...") package_name = params.get("package") status = self._package_download(client, package_name, download_timeout) # 2. Unzip Package if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Download Phase Done!") client.event_publish("OTA: Download Successful!") client.log(iot.LOGINFO, "Unzipping Package...") client.event_publish("OTA: Unzipping Package...") status = self._package_unzip(package_name, package_dir) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Download Failed!") client.event_publish("OTA: Download Failed!") # 3. Read Update Data from JSON File if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Unzip Complete!") client.event_publish("OTA: Package Unzip Successful!") client.log(iot.LOGINFO, "Reading Update Data...") client.event_publish("OTA: Reading Update Data...") status, update_data = self._read_update_json(package_dir) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Unzip Failed!") client.event_publish("OTA: Package Unzip Failed!") # 4. Run Pre-Install if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Data Read Successful!") client.event_publish("OTA: Update Data Read Successfully!") client.log(iot.LOGINFO, "Running Pre-Install...") client.event_publish("OTA: Running Pre-Install...") client.action_progress_update(request.request_id, "Running Pre-Install") client.alarm_publish(ALARM_NAME, ALARM_PRE_INSTALL) if not update_data.get('pre_install', ""): status = iot.STATUS_SUCCESS client.log(iot.LOGINFO, "No Pre-Install specified! " "Continuing.") client.event_publish("OTA: No Pre-Install specified! " "Continuing.") else: status = self._execute(update_data['pre_install'], \ package_dir) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Data Read Failed!") client.event_publish("OTA: Failed to Read Update Data!") # 5. Run Install if status == iot.STATUS_SUCCESS: if update_data.get('pre_install', ""): client.log(iot.LOGINFO, "Pre-Install Complete!") client.event_publish("OTA: Pre-Install Successful!") client.action_progress_update(request.request_id, "Pre-Install Successful") client.log(iot.LOGINFO, "Running Install...") client.event_publish("OTA: Running Install...") client.action_progress_update(request.request_id, "Running Install") client.alarm_publish(ALARM_NAME, ALARM_INSTALL) status = self._execute(update_data['install'], package_dir) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Pre-Install Failed!") client.event_publish("OTA: Pre-Install Failed!") client.action_progress_update(request.request_id, "Pre-Install Failed") # 6. Run Post-Install if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "Install Complete!") client.event_publish("OTA: Install Successful!") client.action_progress_update(request.request_id, "Install Successful") client.log(iot.LOGINFO, "Running Post-Install...") client.event_publish("OTA: Running Post-Install...") client.action_progress_update(request.request_id, "Running Post-Install") client.alarm_publish(ALARM_NAME, ALARM_POST_INSTALL) if not update_data.get('post_install', ""): status = iot.STATUS_SUCCESS client.log(iot.LOGINFO, "No Post-Install specified! " "Continuing.") client.event_publish("OTA: No Post-Install specified! " "Continuing.") else: status = self._execute(update_data['post_install'], \ package_dir) elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Install Failed!") client.event_publish("OTA: Install Failed!") client.action_progress_update(request.request_id, "Install Failed") if status == iot.STATUS_SUCCESS: if update_data.get('post_install', ""): client.log(iot.LOGINFO, "Post-Install Complete!") client.event_publish("OTA: Post-Install Successful!") client.action_progress_update(request.request_id, "Post-Install Successful") status = iot.STATUS_SUCCESS elif not error_notified: error_notified = True client.log(iot.LOGERROR, "Post-Install Failed!") client.event_publish("OTA: Post-Install Failed!") client.action_progress_update(request.request_id, "Post-Install Failed") # 7. Report Final Status if status == iot.STATUS_SUCCESS: client.log(iot.LOGINFO, "OTA Successful!") client.event_publish("OTA: Update Successful!") client.action_progress_update(request.request_id, "Update Successful") client.alarm_publish(ALARM_NAME, ALARM_COMPLETE) status_string = "" else: if update_data and 'error_action' in update_data and \ update_data['error_action']: client.event_publish("OTA: Running install error action!") client.alarm_publish(ALARM_NAME, ALARM_INSTALL_ERROR) client.log(iot.LOGWARNING, "Running install error action!") self._execute(update_data['error_action'], package_dir) client.log(iot.LOGERROR, "OTA Failed!") client.event_publish("OTA: Update Failed!") client.action_progress_update(request.request_id, "Update Failed") client.alarm_publish(ALARM_NAME, ALARM_FAILED) status_string = iot.status_string(status) client.action_acknowledge(request.request_id, status, status_string) # Cleanup if os.path.isdir(package_dir): shutil.rmtree(package_dir) file_name = os.path.join(self._runtime_dir, "download", package_name) if os.path.isfile(file_name): os.remove(file_name) # Unlock the updater try: os.remove(os.path.join(self._runtime_dir, OTA_LOCKFILE)) except (OSError, IOError) as err: error = str(err) print( error + ". This file will block future OTA operations. Please remove it." ) client.log(iot.LOGINFO, \ "Update finished with status {}".format(iot.status_string(status))) # Reboot if requested if update_data and 'reboot' in update_data and \ update_data['reboot'] == 'yes': osal.system_reboot()
def file_download(client, params, user_data): """ Callback for the "file_download" method which downloads a file from the cloud to the local system. """ file_name = None file_path = None result = None blocking = True timeout = 15 message = "AWS provisioning completed" if params: file_name = params.get("file_name") file_path = params.get("file_path", "/install.tar.gz") if file_name and not file_path: file_path = abspath( os.path.join(user_data[0], "download", file_name)) if file_path and not file_name: file_name = os.path.basename(file_path) if file_path.startswith('~'): result = iot.STATUS_BAD_PARAMETER message = "Paths cannot use '~' to reference a home directory" elif not os.path.isabs(file_path): file_path = abspath( os.path.join(user_data[0], "download", file_path)) file_global = params.get("use_global_store", False) if result is None: if file_name and file_path: dir_path = os.path.dirname(file_path) if not os.path.exists(dir_path): try: os.makedirs(dir_path) except (OSError, IOError) as e: result = iot.STATUS_IO_ERROR message = ( "Destination directory does not exist and could " "not be created!") client.error(message) print(e) if result is None: client.log(iot.LOGINFO, "Downloading") result = client.file_download(file_name, file_path, \ blocking=blocking, timeout=timeout, \ file_global=file_global) if result != iot.STATUS_SUCCESS: message = iot.status_string(result) else: result = iot.STATUS_BAD_PARAMETER message = "No file name or destination given" if result == iot.STATUS_SUCCESS: cmd = "./provision_gg" output = {} try: p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) out, err = p.communicate() i = 0 for line in out.split(os.linesep): i = i + 1 output["%03d" % i] = line except Exception as e: print("Error in run_cmd: %s" % e) return (iot.STATUS_SUCCESS, "", output) return (result, message)
def file_upload(client, params, user_data): """ Callback for the "file_upload" method which uploads a file from the cloud to the local system. Wildcards in the file name are supported. """ file_name = None file_path = None result = None if params: file_name = params.get("file_name") file_path = params.get("file_path") if file_name and not file_path: file_path = abspath(os.path.join(user_data[0], "upload", file_name)) if file_path and not file_name: file_name = os.path.basename(file_path) if not file_name and not file_path: file_path = abspath(os.path.join(user_data[0], "upload")) file_name = "upload" if user_data[2]: file_name = (file_path + ".tar").replace("/", "") with tarfile.open((file_path + os.sep + file_name), "w") as tar: for fn in os.listdir(file_path): tar.add((file_path + os.sep + fn), arcname=fn) file_path = abspath(os.path.join(file_path, file_name)) if file_path.startswith('~'): result = iot.STATUS_BAD_PARAMETER message = "Paths cannot use '~' to reference a home directory" elif not os.path.isabs(file_path): file_path = abspath(os.path.join(user_data[0], "upload", file_path)) file_global = params.get("use_global_store", False) if result is None: if file_name and file_path: client.log(iot.LOGINFO, "Uploading {}".format(file_name)) result = client.file_upload(file_path, upload_name=file_name, \ blocking=True, timeout=240, \ file_global=file_global) if result == iot.STATUS_SUCCESS: message = "" if ".tar" in file_name: os.remove(file_path) if user_data[1] and "upload" in file_path: try: if ".tar" in file_name: base = os.path.dirname(file_path) for fn in os.listdir(base): os.remove(base + os.sep + fn) elif file_name == "upload": for fn in os.listdir(file_path): os.remove(file_path + os.sep + fn) else: os.remove(file_path) except (OSError, IOError) as err: error = str(err) print(error + ". Unable to remove file.") else: message = iot.status_string(result) else: result = iot.STATUS_BAD_PARAMETER message = "No file name or location given" return (result, message)