Skip to main content

Allows cron job control and command execution on a remote machine using git infrastructure

Project description

Git syncer

Allows cron job control and command execution on a remote machine using git infrastructure.

Tests Lint PyPI version

👷🏻 Please note, this project is still a work-in-progress 🏗️

Quick start

On your computer, set up the basic repository (checkout the example_project in this repository to see how this should generally look):

  1. Create a private GitHub repository and clone it.
  2. Create a requirements.txt file, and add the git-syncer dependency.
  3. Create a main.py file:
from git_syncer import run
from git_syncer.runnables import register

register()  # Add boot jobs, cron jobs, and remote commands here 🏋🏻‍♂️

if __name__ == "__main__":
    run()
  1. Add a .gitignore file (tip: use gitignore.io). It must contain out/ directory.
  2. Commit and push your changes.

On your remote machine (SSH to it):

  1. Set up GitHub credentials to clone your new repository.
    Highly recommended: instead of providing your own personal GitHub credentials on the remote machine, add an SSH deploy key to your repository . If you choose to do so, check the Allow write access checkbox.
  2. Clone your new repository to the remote machine.
  3. Set up a virtual environment for this project and activate it (using source <venv_dir>/bin/activate).
  4. cd to your repository directory.
  5. Install dependencies using pip install -r requirements.txt (git-syncer should be installed).
  6. ⚠️ THIS STEP WILL OVERRIDE YOUR EXISTING CRONTAB SETTINGS! ⚠️
    Activate the syncer using the CLI command init-syncer.

From now on, you can add new cron jobs and execute remote commands on the remote machine using this git repository. For more details, see the usage section.

Usage

Note: this tool writes logs to ~/logs/git-syncer/.

Runnables

A Runnable is the basic class that the package uses. To define your own custom commands, create your own class, inherit Runnable, and implement the mandatory abstract methods:

# File: my_runnables.py
from git_syncer.models import Runnable


class HelloWorld(Runnable):
    @property
    def verbose_name(self) -> str:
        return "Hello World"

    def run(self) -> str:
        return "This runnable was called!"

...and register your runnable in main.py:

# File: main.py
from git_syncer.runnables import register

from my_runnables import HelloWorld

register(HelloWorld())

Boot jobs

Boot jobs will execute once the remote machine turns on. In order to make a Runnable into a boot job, set the run_on_boot property to True:

class HelloWorld(Runnable):
    @property
    def run_on_boot(self) -> bool:
        return True
    ...

Cron jobs

To create a cron job, inherit the CronJob class, and fill the expression property:

from git_syncer.models import CronJob

class MyCronJob(CronJob):
    @property
    def verbose_name(self) -> str:
        return "Ping"

    @property
    def expression(self) -> str:
        # Every 5 minutes
        return "*/5 * * * *"

    def run(self) -> str:
        return "This job runs every 5 minutes"

Execute jobs on command

In order to make a non-cron runnable execute on the remote machine:

  1. On your local machine, commit an empty file matching your Runnable name under execute folder (for example, if the runnable class name is GetIP, commit a file named execute/get-ip).
  2. Push your changes.
  3. On the next round minute:
    1. The runnable will execute on the remote device,
    2. The execution result will be written in a file matching your runnable name (for example, if the runnable class name is GetIP, the result file will be named execute/get-ip-result.txt, and the execute/get-ip file will be removed).
    3. The changes will be committed and pushed back to the repository.
  4. Wait a few seconds and pull your repository. You will see the execution result in the expected result file.

Expert mode: every minute, in order the check if a non-cron Runnable should be executed, its should_execute method is called (matching file names to the runnable class name). In order to execute your runnable based on different logic, override the should_execute method:

from typing import Set
from git_syncer.models import Runnable
import random

class HelloWorld(Runnable):
    @property
    def verbose_name(self) -> str:
        return "Hello World"

    def run(self) -> str:
        return "This runnable was called!"

     def should_execute(self, inputs: Set[str]) -> bool:
        # Take a look at the base method and implement your own logic.
        return random.randint(1, 100) % 5 == 0

Error handling

👷🏻 TODO

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

git-syncer-1.1.1.tar.gz (15.5 kB view hashes)

Uploaded Source

Built Distribution

git_syncer-1.1.1-py3-none-any.whl (18.1 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page