Example #1
0
    def run(self):
        try:
            while self._stop_read == False:
                logger.info(f'Running binary: {self.executable}')

                proc = subprocess.Popen(self.executable,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.STDOUT,
                                        cwd=self.executable.parent)
                with proc.stdout:
                    self._read_simulator_output(proc.stdout)
                exit_status = proc.wait()
                if exit_status in [0, -13]:
                    logger.info(
                        f'Application terminated with Exit code:{exit_status}')
                else:
                    logger.error(f'Closing serial read')
                    self.close()
                    raise RuntimeError(
                        f'Application stopped with Exit code:{exit_status}')

                if self.run_indefinitely:
                    self.executable = Path(
                        f'{self.initial_exe}_{self.file_version}')
                    self.file_version += 1
                    cmd = f'sudo chmod 777 {self.executable}'.split()
                    result = subprocess.run(cmd,
                                            cwd=self.executable.parent,
                                            capture_output=True)
                    print(result.stdout)
        except Exception as err:  # pylint: disable=broad-except
            logger.error("Unexpected exception: " + str(err))
            traceback.print_exc()
            sys.exit(1)
Example #2
0
    def build(self):
        logger.info("Building image")
        try:
            cmd = f'cmake -S . -B build && cmake --build build --target {self.ota_firmware_path_used_in_job}'
            with open(
                    f'{self.ota_firmware_path_used_in_job}_{datetime.now().strftime("%m%d%H%S")}_build_log.txt',
                    'w') as buildlog:
                result = subprocess.run(cmd,
                                        stdout=buildlog,
                                        stderr=STDOUT,
                                        shell=True,
                                        encoding="utf-8",
                                        cwd=str(self.project.repository_root),
                                        check=True)

            file_path = f'{self.project.repository_root}/build/bin/'
            self.latest_build_firmware_path = f"{file_path}{self.ota_firmware_path_used_in_job}"

        except Exception as e:
            logger.error(f"Error occured: {e}")
            traceback.print_exc()
            return STATUS.ERROR, ''

        logger.info("Build completed")
        return STATUS.PASS, self.latest_build_firmware_path
Example #3
0
    def create_update(self, protocols, deployment_files, role_arn=None, url_expired=3600):
        """
        Create an OTA update job.
        Returns the AWS IoT OTA Update ID.
        :param deviceImageFileName(str): The full path to the image in the device's file system. For devices not using
                a file system any string can be put in here.
        :param streamId (str): The AWS ID of the stream returned from AwsOtaAgent.create_iot_stream().
        :param signerJobId(str): The AWS Job ID of the completed AWS Signer operation. This ID was returned from
                function AwsOtaAgent.sign_firmware_in_s3_bucket().
        :param deploymentFiles (dict):  An AWS CLI compliant dictionary of the deployment file(s)
                                        information to create an OTA update job for.
        """

        # Timeout for the AWS Job service to create an OTA update job.
        AWS_CREATE_OTA_UPDATE_JOB_TIMEOUT = 60
        create_ota_response = {}
        
        create_ota_response = self._awsIotClient.create_ota_update(
            otaUpdateId=str(uuid4()),
            targets=[
                self.project.thing_arn
            ],
            targetSelection='SNAPSHOT',
            roleArn=self.project.ota_update_role_arn,
            files=deployment_files,
            protocols=protocols,
            awsJobPresignedUrlConfig={
                'expiresInSec': url_expired
            }
        )

        # Confirm that the OTA update job is ready.
        timeout_end = time.perf_counter() + AWS_CREATE_OTA_UPDATE_JOB_TIMEOUT
        ota_create_in_progress = True
        ota_update_info = None
        while ota_create_in_progress and time.perf_counter() < timeout_end:
            time.sleep(1)
            otaGetStatusResponse = {}
            otaGetStatusResponse = self._awsIotClient.get_ota_update(
                otaUpdateId = create_ota_response.get('otaUpdateId'))
            ota_update_info = otaGetStatusResponse.get('otaUpdateInfo')

            if ota_update_info.get('otaUpdateStatus') in ('CREATE_COMPLETE', 'CREATE_FAILED'):
                ota_create_in_progress = False

        if ota_create_in_progress == True:
            logger.error(f"Error: OTA update creation timed out for OTA update ID {ota_update_info.get('otaUpdateId')}")
            return None

        # Check for errors and show us what those errors might be.
        if ota_update_info.get('otaUpdateStatus') != 'CREATE_COMPLETE':
            logger.error(f"OTA update creation failed for OTA update ID {ota_update_info.get('otaUpdateId')}")
            if ('errorInfo' in ota_update_info):
                logger.error(f"Code: {ota_update_info.get('errorInfo').get('code')}")
                logger.error(f"Details: {ota_update_info.get('errorInfo').get('message')}")
        else:
            logger.info(f"Created OTA Update ID {ota_update_info.get('otaUpdateId')} (AWS IoT job ID = {ota_update_info.get('awsIotJobId')}).")

        return ota_update_info.get('otaUpdateId')
Example #4
0
 def upload_firmware_to_s3_bucket(self, localPathToFirmware, firmwareFileName):
     """
     Upload a firmware image to the unsigned S3 bucket associated with this OTA agent.
     :param localPathToFirmware(str): The path on the machine this script is running of the firmware image.
     :param firmwareFileName(str): The name of the firmware, this is used as the key in the S3 bucket.
     """
     logger.info('Uploading firmware to S3')
     self._s3Bucket.upload_file(localPathToFirmware, firmwareFileName)
Example #5
0
 def on_connect(client, userdata, flags, rc):
     """ Callback function to notify that the connection is successful
     """
     logger.info(
         "Connected to IoT core. Device should now disconnect then reconnect."
     )
     self.connected_to_iot = True
     mqtt_client.disconnect()
     mqtt_client.loop_stop()
Example #6
0
 def cancel_job(self, jobId):
     """
     Cancel the input job ID.
     :param jobId(str): The AWS IoT job ID to cancel.
     """
     response = {}
     try:
         response = self._awsIotClient.cancel_job(jobId=f'AFR_OTA-{jobId}', comment='OTA integration testing cancellation of incomplete job.', force=True)
         logger.info(f'AFR_OTA-{jobId} job cancelled')
     except Exception as e:
         logger.error("Unable to cancel job with ID: " + jobId)
         logger.error(f"Response: {response}, Exception: {e}")
Example #7
0
 def _read_simulator_output(self, outStream):
     for line in iter(outStream.readline, b''):
         try:
             line = line.decode()
             if self.print_monitor:
                 logger.info(line)
             self.mlog.info(line)
             if self._exit_run:
                 return
         except UnicodeDecodeError:
             logger.warn(f"Unable to debug line: {line}")
         except Exception as e:
             logger.error(f"Exception in binary: {e}")
             self._stop_read = True
             return
Example #8
0
 def get_job_status(self, jobId):
     """
     Get the status of the OTA Update's job from the AWS IoT jobId.
     :param jobId(str): The AWS IoT Job ID to get the status of.
     :return: The job status and the reason for the status in a namedtuple.
     """
     JobStatus = namedtuple('JobStatus', 'status reason')
     try:
         response = {}
         response = self._awsIotClient.describe_job_execution(jobId=jobId, thingName=self.project.thing_name)
     except Exception as e:
         logger.warning(f"ID:{jobId[-12:]} aws iot describe-job-execution failed. Err: {e}")
         return JobStatus('UNDEFINED', 'aws iot describe-job-execution failed.')
     executionResponse = response['execution']
     job_status = JobStatus(executionResponse['status'], executionResponse['statusDetails'].get('detailsMap', {}).get('reason', ''))
     logger.info(f"ID:{jobId[-12:]} {job_status}")
     if executionResponse['status'] == "SUCCEEDED" or executionResponse['status'] == "IN_PROGRESS":
         logger.debug(executionResponse)
     return job_status
Example #9
0
    def __init__(self, filename, logfilename=None):
        Thread.__init__(self)

        self.print_monitor = False  # Set this to true to get output on CLI
        self._stop_read = False
        self._exit_run = False
        self.executable = Path(filename)
        self.initial_exe = filename
        self.run_indefinitely = True  # Set this to false for 1 run
        self.file_version = 2
        if logfilename:
            self.log_output = logfilename
        else:
            self.log_output = f'{datetime.now().strftime("%m%d%H%S")}_logfile.txt'

        self.clear_file(self.log_output)
        logger.info(f'Logging the run to {self.log_output}')
        self.mlog = setup_logger(name='monitor',
                                 file=True,
                                 log_file=self.log_output,
                                 format='raw',
                                 terminator='')
Example #10
0
    def get_ota_update_result(self, ota_update_id, timeout, sleep_time=5):
        '''
        Non blocking call to get ota update status. Function return upon job completion.
        :param ota_update_id: AWS OTA job id
        :param timeout: Time after which the job fails
        :return: Status os the update once it is finished
        '''
        seconds = 0
        summary = None

        # Get the AWS Iot Job ID
        response = {}
        response = self._awsIotClient.get_ota_update(otaUpdateId=ota_update_id)
        job_id = response['otaUpdateInfo']['awsIotJobId']

        finished_job_statuses = {'CANCELED', 'SUCCEEDED', 'FAILED', 'REJECTED', 'REMOVED'}
        start = time.perf_counter()
        summary = None
        while True:
            job_status = self.get_job_status(job_id)
            if job_status.status in finished_job_statuses:
                # logger.error(f"Version received from the cloud is : {self.get_version_number(job_id)}")
                break
            else:
                time.sleep(sleep_time)

            end = time.perf_counter()
            if end - start > timeout:
                logger.error(f"Timeout on OTA Update's job. (Timeout setting: {timeout})")
                logger.info(f'start: {start}, end: {end}')
                self.cancel_job(job_id)
                summary = 'Timeout on OTA Update\'s job.'
                break

        self.delete_ota_update(ota_update_id)
        return job_status, summary