Remote task execution tool

Related tags

gunnery
Overview

Gunnery

Build Status

Gunnery is a multipurpose task execution tool for distributed systems with web-based interface.

If your application is divided into multiple servers, you are probably connecting to them via ssh and executing over and over the same commands. Clearing caches, restarting services, backups, checking health. Wouldn't it be cool if you could do that from browser or smartphone? Gunnery is here for you!

Features

  • Support for a wide variety of tools
    Thanks to simple design it's possible to integrate with tools like capistrano, ant, phing, fabric, make, or puppet
  • Designed for distributed systems
    Handles multi-environment applications with many servers
  • Usable for deployment, service control, backups
    Every command executed in shell can be turned into a Gunnery task
  • Secure remote execution
    Certificate based authentication provides secure access to your network
  • Web-based interface
    Clear, responsive interface pleases eye and enables usage on mobile devices
  • User notifications
    Team members will be notified when tasks are executed
  • Permission system
    Create custom user groups and limit their access to specific environments or tasks

Screenshots

test test test

Documentation

Step by step install instructions, and usage notes are available in documentation.

Feedback

Please submit feedback, bugs, feature requests here.

Contribute

Vagrant configuration is available for easy development, included Puppet rules will build complete environment. Read more

Issues
  • Getting started

    Getting started

    I would really like to test this as it seems a useful app but following the steps (either shortcut or longer installation) both leave me at the same spot with seemingly not reading the settings properly. It complains about SECRET_KEY being empty and DATABASE/ENGINE settings etc. so seems to be reading from /var/gunnery/virtualenv/production/local/lib/python2.7/site-packages/django/conf/ when I believe it should read from /var/gunnery/gunnery/gunnery/settings?

    Basically, following the steps always fails at the "python manage.py syncdb" step.

    The instructions I personally find really poor, unless this is only meant for people who have a deep understanding of all the various apps used for it to work? In a previous issue about poor documentation one reply is "For now, I recommend looking at puppet rules, they will get you running application in minutes.". I don't think anyone could get a running app in minutes on this, especially without knowing puppet really well also.

    For now I have to give up as I have spent almost a whole day on this which is a shame, but until following the instructions works, I cannot spend more time on it. I hope you can tell me something really obvious I am doing wrong but if I am, it is not in the docs.

    opened by jmilburn 16
  • 400 Bad Request

    400 Bad Request

    hey,

    just ran the install on a ubuntu 12.04 and a 13.10 box ( aws ec2 instance )

    and i am getting a 400 bad request.

    does it run on 8080 or 80 ?

    bug 
    opened by dholdaway 10
  • Submodule 'puppet-module-python.git'

    Submodule 'puppet-module-python.git'

    Hi, I am getting this error while cloning the repo "fatal: repository 'https://github.com/puppetmodules/puppet-module-python.git/' not found Clone of 'https://github.com/puppetmodules/puppet-module-python.git' into submodule path 'puppet/modules/python' failed"

    Turns out https://github.com/puppetmodules/puppet-module-python has been deleted or made private, is there an alternative to above module?

    bug 
    opened by agaurav 7
  • Clicking on + for

    Clicking on + for "add server" causes Django to silently hang

    Clicking on plus sign causes this request to spawn and never finish: http://10.211.55.7:8080/modal_form/a:/environment/1/server/ It halts whole UWSGI process, no requests can be made, until UWSGI is killed (SIGTERM does nothing). All requests timeout with 504.

    Nothing new appears in logs when this happens. Not even nginx request.

    I've tried this in development environment, i.e. by running python manage.py runserver and issuing curl request, which causes it to hang too and Python must be killed. Note that by using curl I'm not even logged in. The request doesn't even shop up on the screen.

    [email protected]:/var/gunnery/gunnery# python manage.py runserver
    Validating models...
    
    0 errors found
    June 10, 2014 - 12:43:11
    Django version 1.6.2, using settings 'gunnery.settings.production'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CONTROL-C.
    [10/Jun/2014 12:43:16] "HEAD / HTTP/1.1" 302 0
    

    Second terminal window:

    [email protected]:/var/gunnery/log# curl localhost:8000/ -I
    HTTP/1.0 302 FOUND
    Date: Tue, 10 Jun 2014 10:43:16 GMT
    Server: WSGIServer/0.1 Python/2.7.3
    Vary: Cookie
    X-Frame-Options: SAMEORIGIN
    Content-Type: text/html; charset=utf-8
    Location: http://localhost:8000/account/login/?next=/
    
    [email protected]:/var/gunnery/log# curl localhost:8000/modal_form/a:/environment/1/server/ -I
    # hangs....
    

    It is a clear installation. I just created Department, Server roles, Application, Environment and clicking on + in chosen Environment causes this.

    I'm not really familiar with Django or Python, is there something I can do to nail down this issue?

    Also, I don't know if it can be related - issuing service celeryd stop does nothing, it waits. I must ctrl+c the stopping process and issue it again. Workers stop properly on this second try. Always. Doesn't matter if I have one worker or 3 of them. I don't know if clicking on Add server causes some background task to fire... so that's why I'm mentioning this.

    [email protected]:/var/gunnery/log# /etc/init.d/celeryd start
    celery multi v3.1.7 (Cipater)
    > Starting nodes...
            > [email protected]: OK
    [email protected]:/var/gunnery/log# /etc/init.d/celeryd stop
    celery multi v3.1.7 (Cipater)
    > Stopping nodes...
            > [email protected]: TERM -> 5685
    > Waiting for 1 node -> 5685....................................................................................^C
    Session terminated, terminating shell... ...terminated.
    
    [email protected]:/var/gunnery/log# /etc/init.d/celeryd stop
    celery multi v3.1.7 (Cipater)
    > Stopping nodes...
            > [email protected]: TERM -> 5685
    > Waiting for 1 node -> 5685.....
            > [email protected]: OK
    

    VM: Debian 3.2.0-4-amd64 Python 2.7.3 (default, Mar 13 2014, 11:03:55) Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:30] [kernel-poll:true] RabbitMQ 2.8.4

    If you need anything more, let me know.

    bug 
    opened by daliborfilus 7
  • Better documentation

    Better documentation

    I'd really like to see some better documentation about setting this up and getting it running. If you're not familiar with the db layout, or any python apps, it's a real nightmare navigating how to install it.

    documentation 
    opened by jaxxstorm 4
  • static files not found

    static files not found

    Hello,

    I am following http://gunnery.readthedocs.org/en/latest/install.html documentation to get server up and running. I am able to get it running.

    But, css, jquery, bootstrap files are not found http://localhost:8000/static/css/bootstrap.css Also, nothing happens if I click on "Create first".

    what could be the reason / what do i need to change ?

    thanks, Manjiri

    opened by manjirinamjoshi 3
  • Vagrant Box outdated

    Vagrant Box outdated

    I ran into the issue that when I ran vagrant up with a fresh git clone nothing would provision. I would get a ton of errors with ubuntu links that would 404 in terminal. I am assuming that the vm Box that is currently in the Vagrantfile is outdated which is causing the issues.

    I decided to change the box that I would run on to ubuntu/trusty64 and everything seems to be fine. Would updating the box to a newer version of ubuntu be something considered to help fix the vagrant?

    bug 
    opened by ddymko 2
  • Setup guidelines create init.d for uwsgi with incorrect path to gunnery.ini

    Setup guidelines create init.d for uwsgi with incorrect path to gunnery.ini

    The setup directions at http://gunnery.readthedocs.org/en/latest/install.html write gunnery.ini to /etc/uwsgi/apps-enabled but the init.d script for uwsgi points to sites-enabled.

    The dir needs to be renamed in the docs.

    bug documentation 
    opened by kalleth 2
  • change celery worker & concurrency settings

    change celery worker & concurrency settings

    We have 80 machines that need to execute the command in a task.

    And we found out that there only 8 concurrency worker will run in a same time.

    I know celery is the key of gunnery task and I found some config in puppet file https://github.com/gunnery/gunnery/blob/master/puppet/manifests/hieradata/common.yaml

    celery::workers : 1 celery::concurrency : 8

    We are trying to increase those number after already installed. Any hint will be great. Thanks.

    question 
    opened by chrisLeeTW 2
  • Add Create Own SSH Certificate Feature.

    Add Create Own SSH Certificate Feature.

    Thanks for this great solution.

    Due to our org system security policy. Our org need to regenerate all these ssh certificate after one month.

    So If there can add our own ssh cert that will be great.

    Hope that can consider this advice. thanks.

    opened by chrisLeeTW 2
  • Bump django from 1.6.7 to 2.2.24 in /requirements

    Bump django from 1.6.7 to 2.2.24 in /requirements

    Bumps django from 1.6.7 to 2.2.24.

    Commits
    • 2da029d [2.2.x] Bumped version for 2.2.24 release.
    • f27c38a [2.2.x] Fixed CVE-2021-33571 -- Prevented leading zeros in IPv4 addresses.
    • 053cc95 [2.2.x] Fixed CVE-2021-33203 -- Fixed potential path-traversal via admindocs'...
    • 6229d87 [2.2.x] Confirmed release date for Django 2.2.24.
    • f163ad5 [2.2.x] Added stub release notes and date for Django 2.2.24.
    • bed1755 [2.2.x] Changed IRC references to Libera.Chat.
    • 63f0d7a [2.2.x] Refs #32718 -- Fixed file_storage.test_generate_filename and model_fi...
    • 5fe4970 [2.2.x] Post-release version bump.
    • 61f814f [2.2.x] Bumped version for 2.2.23 release.
    • b8ecb06 [2.2.x] Fixed #32718 -- Relaxed file name validation in FileField.
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump django-debug-toolbar from 1.2.1 to 1.11.1 in /requirements

    Bump django-debug-toolbar from 1.2.1 to 1.11.1 in /requirements

    Bumps django-debug-toolbar from 1.2.1 to 1.11.1.

    Changelog

    Sourced from django-debug-toolbar's changelog.

    1.11.1 (2021-04-14)

    • Fixed SQL Injection vulnerability, CVE-2021-30459. The toolbar now calculates a signature on all fields for the SQL select, explain, and analyze forms.

    1.11 (2018-12-03)

    • Use defer on all <script> tags to avoid blocking HTML parsing, removed inline JavaScript.
    • Stop inlining images in CSS to avoid Content Security Policy errors altogether.
    • Reformatted the code using black <https://github.com/ambv/black>__.
    • Added the Django mail panel to the list of third-party panels.
    • Convert system check errors to warnings to accomodate exotic configurations.
    • Fixed a crash when explaining raw querysets.
    • Fixed an obscure unicode error with binary data fields.
    • Added MariaDB and Python 3.7 builds to the CI.

    1.10.1 (2018-09-11)

    • Fixed a problem where the duplicate query detection breaks for non-hashable query parameters.
    • Added support for structured types when recording SQL.
    • Made Travis CI also run one test no PostgreSQL.
    • Added fallbacks for inline images in CSS.
    • Improved cross-browser compatibility around URLSearchParams usage.
    • Fixed a few typos and redundancies in the documentation, removed mentions of django-debug-toolbar's jQuery which aren't accurate anymore.

    1.10 (2018-09-06)

    • Removed support for Django < 1.11.
    • Added support and testing for Django 2.1 and Python 3.7. No actual code changes were required.
    • Removed the jQuery dependency. This means that django-debug-toolbar now requires modern browsers with support for fetch, classList etc.
    • Added support for the server timing header.
    • Added a differentiation between similar and duplicate queries. Similar queries are what duplicate queries used to be (same SQL, different parameters).
    • Stopped hiding frames from Django's contrib apps in stacktraces by default.

    ... (truncated)

    Commits
    • bc08f69 Merge pull request from GHSA-pghf-347x-c2gj
    • c201ce3 django-debug-toolbar 1.11
    • 0a75be1 Update the change log
    • a4a5393 Merge pull request #1121 from matthiask/mariadb
    • 48a0e2e Reformat settings using black
    • 901aed7 Mark binary payload as binary (same thing BinaryField.get_db_prep_value does)
    • ad091e6 Test with a real BinaryField
    • 2f3193e Remove the MySQL USER
    • 762e5d9 Run tests with MariaDB too on Travis CI
    • e78ac8c Merge pull request #1107 from dbowd/patch-1
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Fix simple typo: specyfic -> specific

    Fix simple typo: specyfic -> specific

    Closes #52

    opened by timgates42 0
  • Fix simple typo: specyfic -> specific

    Fix simple typo: specyfic -> specific

    There is a small typo in docs/develop.rst. Should read specific rather than specyfic.

    opened by timgates42 0
  • Bump ecdsa from 0.11 to 0.13.3 in /requirements

    Bump ecdsa from 0.11 to 0.13.3 in /requirements

    Bumps ecdsa from 0.11 to 0.13.3.

    Release notes

    Sourced from ecdsa's releases.

    ecdsa 0.13.3

    Fix CVE-2019-14853 - possible DoS caused by malformed signature decoding Fix CVE-2019-14859 - signature malleability caused by insufficient checks of DER encoding

    Also harden key decoding from string and DER encodings.

    ecdsa 0.13.2

    Restore compatibility of setup.py with Python 2.6 and 2.7.

    ecdsa 0.13.1

    Fix the PyPI wheel - the old version included .pyc files.

    ecdsa 0.13

    Fix the argument order for Curve constructor (put openssl_name= at the end,
    with a default value) to unbreak compatibility with external callers who used
    the 0.11 convention.

    ecdsa 0.12

    Switch to Versioneer for version-string management (fixing the broken ecdsa.__version__ attribute). Add Curve.openssl_name property. Mention secp256k1 in README, test against OpenSSL. Produce "wheel" distributions. Add py3.4 and pypy3 compatibility testing. Other minor fixes.

    Changelog

    Sourced from ecdsa's changelog.

    • Release 0.14.1 (06 Nov 2019)

    Remove the obsolete six.py file from wheel

    • Release 0.14 (06 Nov 2019)

    Bug fixes: Strict checking of DER requirements when parsing SEQUENCE, INTEGER, OBJECT IDENTIFIER and BITSTRING objects. DER parsers now consistently raise UnexpectedDER exception on malformed DER encoded byte strings. Make sure that both malformed and invalid signatures raise BadSignatureError. Ensure that all SigningKey and VerifyingKey methods that should accept bytes-like objects actually do accept them (also avoid copying input strings). Make SigningKey.sign_digest_deterministic use default object hashfunc when none was provided. encode_integer now works for large integers. Make encode_oid and remove_object correctly handle OBJECT IDENTIFIERs with large second subidentifier and padding in encoded subidentifiers.

    New features: Deterministic signature methods now accept extra_entropy parameter to further randomise the selection of k (the nonce) for signature, as specified in RFC6979. Recovery of public key from signature is now supported. Support for SEC1/X9.62 formatted keys, all three encodings are supported: "uncompressed", "compressed" and "hybrid". Both string, and PEM/DER will automatically accept them, if the size of the key matches the curve. Benchmarking application now provides performance numbers that are easier to compare against OpenSSL. Support for all Brainpool curves (non-twisted).

    New API: CurveFp: __str__ is now supported. SigningKey.sign_deterministic, SigningKey.sign_digest_deterministic and generate_k: extra_entropy parameter was added Signature.recover_public_keys was added VerifyingKey.from_public_key_recovery and VerifyingKey.from_public_key_recovery_with_digest were added VerifyingKey.to_string: encoding parameter was added VerifyingKey.to_der and SigningKey.to_der: point_encoding parameter was added. encode_bitstring: unused parameter was added remove_bitstring: expect_unused parameter was added SECP256k1 is now part of curves * import Curves: __repr__ is now supported VerifyingKey: __repr__ is now supported

    Deprecations: Python 2.5 is not supported any more - dead code removal.

    ... (truncated)
    Commits
    • 7add221 update NEWS file for 0.13.3
    • 5c4c74a Merge pull request #124 from tomato42/backport-sig-decode
    • 1eb2c04 update README with error handling of from_string() and from_der()
    • b95be03 execute also new tests in Travis
    • 99c907d harden also key decoding
    • 3427fa2 ensure that the encoding is actually the minimal one for length and integer
    • 563d2ee make variable names in remove_integer more aproppriate
    • 14abfe0 explicitly specify the distro to get py26 and py33
    • 9080d1d fix length decoding
    • 897178c give the same handling to string encoded signatures as to DER
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot ignore this [patch|minor|major] version will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • conn error

    conn error

    TestConnectionTask server_id=5: <type 'exceptions.TypeError'> cannot concatenate 'str' and 'long' objects
    Traceback (most recent call last):
      File "backend/tasks.py", line 240, in run
        transport = self.create_transport(server_id)
      File "backend/tasks.py", line 259, in create_transport
        transport = ssh.SSHTransport(server)
      File "backend/ssh.py", line 26, in __init__
        self.secure_files = SecureFileStorage(self.server.environment_id)
      File "backend/securefile.py", line 12, in __init__
        'private_key': PrivateKey(uid),
      File "backend/securefile.py", line 33, in __init__
        name_hash = md5(settings.SECRET_KEY + self.prefix + uid).hexdigest()
    TypeError: cannot concatenate 'str' and 'long' objects
    [2018-01-22 09:16:55,656: INFO/MainProcess] Task backend.tasks.TestConnectionTask[5afd2b89-afee-45ac-bb9e-66ab800ef0b8] succeeded in 0.183372716001s: (False, u'Unknown error')
    
    
    opened by cucy 0
  • Code clean-up

    Code clean-up

    Hi @Eyjafjallajokull I know you want to do some re factoring, are you ok to do some code clean-ups first?

    My propositions:

    1. If you want to follow PEP 8 some changes/fixes needed.
    2. Some unused import/variables.
    3. General JS clean up(not necessary now, can cause potential issues but you know I like good JS :)
    4. Some general fixes.

    If you ok with that can prepare PR's to all of them. It's not rocket science, I just want to use some PyCharm features(code inspections report). Please let me know what do you think.

    opened by senkal 1
  • Schedule

    Schedule

    It would be awesome if task execution could be either scheduled from the web interface or executed from console and scheduled with cron.

    feature 
    opened by sagikazarmark 4
  • Setup guidelines do not explain replacements for nginx configuration

    Setup guidelines do not explain replacements for nginx configuration

    Specifically, the erb for the nginx configuration is:

      <% if @static_only_collected %>
                    try_files /gunnery$uri /404;
                    <% else %>
                    try_files $uri /core$uri /static$uri /<%= @app_name %>$uri /404;
                    <% end %>
    
                    <% if @gzip_enable %>
                    gzip on;
                    gzip_min_length 1100;
                    gzip_buffers 4 32k;
                    gzip_types text/plain application/x-javascript text/xml text/css;
                    gzip_vary on;
                    <% end %>
    
                    <% if @cache_headers_enable %>
                    expires 30d;
                    add_header Cache-Control "public";
                    <% end %>
    

    It'd be good to know which of these sections to leave :)

    documentation 
    opened by kalleth 1
  • Setup guidelines do not setup python virtualenv

    Setup guidelines do not setup python virtualenv

    http://gunnery.readthedocs.org/en/latest/install.html when following the non-puppet version of install steps do not create a virtualenv directory.

    I needed to apt-get install python-virtualenv and then virtualenv env to create it. Then my pip install -r requirements/production.txt became sudo -u gunnery env/bin/pip install -r requirements/production.txt.

    documentation 
    opened by kalleth 3
Releases(v0.2-alpha)
  • v0.2-alpha(Sep 17, 2014)

    • Extend permission system by adding user groups
    • Code refactoring of modal windows
    • Improved test coverage to 69%
    • Bugfixes: sidebar, modal windows, user lists

    Upgrading

    After updating code to this version run python manage.py migrate --merge in application directory to update database schema. Migrations will add 2 default groups to every department and assign all users to User groups. It is necessary to manually assign Admin group to selected users, because this information is not migrated from v0.1.

    Source code(tar.gz)
    Source code(zip)
  • v0.1-alpha(Aug 18, 2014)

    This is first release of Gunney project, features:

    • organize applications and users in departments
    • manage many servers using roles
    • execute remote commands via SSH
    Source code(tar.gz)
    Source code(zip)
A simple scheduler tool that provides desktop notifications about classes and opens their meet links in the browser automatically at the start of the class.

This application provides desktop notifications about classes and opens their meet links in browser automatically at the start of the class.

Anshit 13 Mar 23, 2021
Crontab jobs management in Python

Plan Plan is a Python package for writing and deploying cron jobs. Plan will convert Python code to cron syntax. You can easily manage you

Shipeng Feng 1.1k Aug 22, 2021