adop 0.0.9
Automatic deployment on-prem from zip archives
License: BSD-3-Clause
Keywords: rest,api,post,zip,auto,deploy,on-prem

====
adop
====

* PyPI: https://pypi.org/project/adop/
* Downloads: https://gitlab.com/fholmer/adop/-/packages
* Documentation: https://fholmer.gitlab.io/adop
* Source Code: https://gitlab.com/fholmer/adop
* License: BSD License

Summary
=======

Automatic deployment on-prem from zip archives.

Features
========

* A REST API to upload, download and deploy zip-files.
* Listens for webhook requests, to continuously deploy zip-files on commits.
* Includes "package manager" like commands to upload and installing zip-files.

Warning
=======

* This is a beta version. Not ready for production.


Installation
============

Open command line and and install using pip:

.. code-block:: console

    $ pip install adop[server]


Usage
=====

adop is available as console script and library module

.. code-block:: console

    $ adop -h
    $ python -m adop -h

Serve the REST-API:

.. code-block:: console

    $ adop serve-api
    Serving on http://127.0.0.1:8000

Find the generated authorization token

* Windows

  .. code-block:: doscon

    > type %USERPROFILE%\.adop\adop.ini | findstr write_token

* Linux

  .. code-block:: console

    $ cat ~/.adop/adop.ini | grep write_token

Test the REST-API with ``curl``


* Windows

  .. code-block:: doscon

    > set ADOP_TOKEN=copy-paste-token-here
    > curl -H "Token: %ADOP_TOKEN%" "http://127.0.0.1:8000/api/v1/test"

* Linux

  .. code-block:: console

    $ export ADOP_TOKEN=copy-paste-token-here
    $ curl -H "Token: $ADOP_TOKEN" "http://127.0.0.1:8000/api/v1/test"

Upload and deploy a zip-library:

.. code-block:: console

    $ curl \
      -H "Token: $ADOP_TOKEN" \
      -H "Zip-Tag: 0.1.0" \
      --data-binary "@work/mylib.zip" \
      "http://127.0.0.1:8000/api/v1/deploy/zip/mylib"


Zip file layout
===============

Zip files with exactly one root directory are valid and can be distributed.
The root directory name must be unique if many zip files are to be distributed.

Example of a valid zip file layout:

.. code-block:: kal

    /mylib/
        /README.rst
        /main.py
        /mypackage1/
            /__init__.py
            /__main__.py
        /mypackage2/
            /__init__.py
            /__main__.py

Following example is **not** valid:

.. code-block:: kal

    /README.rst
    /mylib1/
        /__init__.py
        /__main__.py
    /mylib2/
        /__init__.py
        /__main__.py

API
===

Endpoints
---------

========================================= ========= =============================
Description                               Method    Endpoint
========================================= ========= =============================
Check that the API is available.          GET       /api/v1/test
Shasum for all deployed zip-files.        GET       /api/v1/state
Shasum for given deployed root.           GET       /api/v1/state/<root>
Known tags for given root.                GET       /api/v1/tags/<root>
Check specific tag for given root.        GET       /api/v1/tags/<root>/<tag>
List available zip-files.                 GET       /api/v1/list/zip
List available zip-files for given root.  GET       /api/v1/list/zip/<root>
Start auto-fetch routine if enabled.      GET       /api/v1/trigger/fetch
Start auto-fetch routine if enabled.      POST      /api/v1/trigger/fetch/<root>
Download zip-file with given root.        GET       /api/v1/download/zip/<root>
Upload a zip-file without deploying it.   POST/PUT  /api/v1/upload/zip/<root>
Upload and deploy a zip-file.             POST/PUT  /api/v1/deploy/zip/<root>
Deploy a preloaded zip-file.              GET       /api/v1/deploy/zip/<root>
Zip-file unpacking progress.              GET       /api/v1/progress
========================================= ========= =============================

**<root>**
    Name of the root directory in the zip-file.

Headers
-------

=========== ====================================== ============================
Header      Description                            Endpoint
=========== ====================================== ============================
Token       The authorization token for this API.  - All
Zip-Sha256  content hash of the zip-file to        - GET /api/v1/deploy/zip
            deploy.
Zip-Tag     Tag the Shasum. Optional.              - POST/PUT /api/v1/upload/zip
                                                   - GET/POST/PUT /api/v1/deploy/zip
Zip-Root    Name of root directory in zip-file     - POST/PUT /api/v1/upload/zip
            Optional.                              - POST/PUT /api/v1/deploy/zip
=========== ====================================== ============================

Result
------

The result is encoded as a json object. Most endpoints will return an object
with ``result`` and ``result_code`` as keywords.

.. code-block:: console

    $ curl \
      -H "Token: paste-token-here" \
      http://127.0.0.1:8000/api/v1/test
    {
      "result": "It works", 
      "result_code": 0
    }

Endpoints that take a long time will stream a progress log until
the result is returned.

.. code-block:: console

    $ curl \
      -H "Token: paste-token-here" \
      --data-binary "@work/mylib.zip" \
      http://127.0.0.1:8000/api/v1/deploy/zip/mylib
    // root: mylib
    // store data
    // verify data
    // verify root dir
    // verify zip data
    // zip root: 'mylib'
    // unpack zip data
    // remove untracked files
    {"root": "mylib", "result": "Success", "result_code": 0}


The Json specification does not support comments,
so the client must ignore lines prefixed with ``//`` before decoding.

.. code-block:: console

    $ curl \
      -H "Token: paste-token-here" \
      --data-binary "@work/mylib.zip" \
      http://127.0.0.1:8000/api/v1/deploy/zip/mylib \
      | grep -v // \
      | python -m json.tool
    {
        "root": "mylib",
        "result": "Success",
        "result_code": 0
    }


Status and result codes
-----------------------

=========== ============ =================================================
HTTP status result_code  Descripton
=========== ============ =================================================
200         0            OK. Indicates that the request has succeeded.
200         1            Fail. The request has succeeded but result was
                         unsuccessful.
200         2            In progress. The request as been interrupted and
                         returned to early to give the final result code.
401         4            Unauthorized. Invalid token.
500         5            Internal Error
=========== ============ =================================================

Client side
===========

Define requirements in a ``requires.ini`` file

.. code-block:: text

  [requires]
  mylib = tag:0.1.0


Define the remote and install locations:

.. code-block:: console

  $ export ADOP_TOKEN=copy-paste-token-here
  $ adop config add-remote myserver http://127.0.0.1:8000/api/v1 -e ADOP_TOKEN
  $ adop config add-install mylibs ./lib/auto ./lib/.cache

And then install:

.. code-block:: console

  $ adop zip install requires.ini --remote myserver --install mylibs