예제 #1
0
def telemetry(func):
    """
    Automagica Activity Telemetry

    This allows us to collect information on the usage of 
    certain Automagica functionalities in order for us to keep improving 
    the software. If you would like to disable telemetry, make sure the 
    environment variable 'AUTOMAGICA_NO_TELEMETRY' is set. That way no
    information is being shared with us.
    """
    if not os.environ.get("AUTOMAGICA_NO_TELEMETRY") and not os.environ.get(
            "AUTOMAGICA_URL"):
        if func.__doc__:
            name = func.__doc__.split("\n")[0]
        else:
            name = func.__name__

        data = {
            "activity": name,  # Name of the activity
            "machine_id": getnode(),  # Unique (anonymous) identifier
            "os": {
                "name": os.name,  # Operating system name
                "platform": platform.system(),  # Platform OS
                "release": platform.release(),  # Version OS
            },
        }

        try:
            _ = http_client.post("https://telemetry.automagica.com/",
                                 json=data,
                                 timeout=1)
        except Exception:
            logging.debug("Telemetry error")
예제 #2
0
    def _alive_thread(self, interval=30):
        headers = {"bot_secret": self.config.values["bot_secret"]}

        while True:
            try:
                _ = http_client.post(
                    self.config.values["portal_url"] + "/api/bot/alive",
                    headers=headers,
                )
                self.config.logger.info("Sent alive to Automagica Portal.")
            except:
                self.config.logger.exception(
                    "Could not reach Automagica Portal.")

            sleep(interval)
예제 #3
0
    def _runner_thread(self, interval=10, retry_interval=5 * 60):
        headers = {"bot_secret": self.config.values["bot_secret"]}

        NotificationWindow(self, message="Bot started!")

        while True:
            try:
                # Get next job
                r = http_client.get(
                    self.config.values["portal_url"] + "/api/job/next",
                    headers=headers,
                )

                job = r.json()

                # We got a job!
                if job:
                    NotificationWindow(
                        self, message=f"Received job {job['job_id']}"
                    )
                    self.config.logger.info(f"Received job {job['job_id']}")

                    # Create directory to store job-related files
                    local_job_path = os.path.join(
                        os.path.expanduser("~"), ".automagica", job["job_id"]
                    )
                    os.makedirs(local_job_path)
                    os.makedirs(os.path.join(local_job_path, "input"))
                    os.makedirs(os.path.join(local_job_path, "output"))

                    # Download job input files
                    for job_file in job["job_files"]:

                        # Download file
                        r = http_client.get(job_file["url"])

                        # Save locally in the input folder in the job folder
                        with open(
                            os.path.join(
                                local_job_path, "input", job_file["filename"]
                            ),
                            "wb",
                        ) as f:
                            f.write(r.content)

                    if job.get("parameters"):
                        with open(
                            os.path.join(
                                local_job_path, "input", "parameters.py"
                            ),
                            "w",
                        ) as f:
                            f.write(job["parameters"])

                    entrypoint = job["job_entrypoint"]

                    # IPython Notebook / Automagica Lab
                    if entrypoint.endswith(".ipynb"):
                        output, returncode = self.run_notebook(
                            os.path.join(local_job_path, "input", entrypoint,),
                            local_job_path,
                        )

                    # Python Script File
                    elif entrypoint.endswith(".py"):
                        output, returncode = self.run_script(
                            os.path.join(local_job_path, "input", entrypoint),
                            local_job_path,
                        )

                    # Automagica FLow
                    elif entrypoint.endswith(".json"):
                        output, returncode = self.run_flow(
                            os.path.join(local_job_path, "input", entrypoint),
                            local_job_path,
                        )

                    # Other command
                    else:
                        output, returncode = self.run_command(
                            entrypoint, local_job_path
                        )

                    # Write console output
                    with open(
                        os.path.join(local_job_path, "output", "console.txt"),
                        "w",
                    ) as f:
                        f.write(output)

                    if returncode == 0:
                        job["status"] = "completed"
                        NotificationWindow(
                            self, message=f"Completed job {job['job_id']}"
                        )
                        self.config.logger.info(
                            f"Completed job {job['job_id']}"
                        )

                    else:
                        job["status"] = "failed"
                        NotificationWindow(
                            self, message=f"Failed job {job['job_id']}"
                        )
                        self.config.logger.info(f"Failed job {job['job_id']}")

                    # Make list of output files after job has ran
                    output_files = []

                    for file_path in os.listdir(
                        os.path.join(local_job_path, "output")
                    ):
                        output_files.append({"filename": file_path})

                    # Prepare finished job package
                    data = {
                        "bot_secret": self.config.values["bot_secret"],
                        "job_id": job["job_id"],
                        "job_status": job["status"],
                        "job_output_files": output_files,
                        "job_output": output,
                    }

                    # Update Portal on job status and request S3 signed URLs to upload job output files
                    r = http_client.post(
                        self.config.values["portal_url"] + "/api/job/status",
                        json=data,
                        headers=headers,
                    )

                    data = r.json()

                    # Upload job output files
                    for output_file in data["output_files"]:
                        with open(
                            os.path.join(
                                local_job_path,
                                "output",
                                output_file["filename"],
                            ),
                            "rb",
                        ) as f:
                            _ = http_client.post(
                                output_file["payload"]["url"],
                                data=output_file["payload"]["fields"],
                                files={
                                    "file": (
                                        os.path.join(
                                            local_job_path,
                                            "output",
                                            output_file["filename"],
                                        ),
                                        f,
                                    )
                                },
                            )

                # We did not get a job!
                else:
                    sleep(interval)
                    keyboard.press("f13")  # Prevent lock

            except:
                NotificationWindow(self, message="Connection error")
                self.config.logger.exception(
                    f"Could not reach Automagica Portal. Waiting {interval} second(s) before retrying."
                )
                sleep(interval)