Search code examples
pythonraspberry-picontinuous-integrationdevicecd

Is there a python edge software update tool?


So I have a simple app written in python and running on a set (10) Raspberry Pis.

  • It is a folder with one runnable script.
  • I want to have on my external server with public IP some kind of CI/CD like service that would deploy updates to all edge nodes and restart my app on them.
  • Internet is rare on edge devices thus I want to push updates when I push some button on the server

Is there such thing for python programs that are meant to run on edge devices?


Solution

  • As I understand the main problem is to update and run some script on multiple Raspberry Pi boards, correct?

    There are a lot of ready-made solution like dokku or piku. Both allows you to do git push deployments to your own servers (manually).

    Or you can develop your own solution, using GitHub webhooks or some HTML form (for manual push) and Flask web-server that will do CI/CD steps internally.

    You'll need to run script like above on each node/board. And configure Webhook with URL similar to: http://your-domain-or-IP.com:8000/deploy-webhook but with different port per node.

    Or you can open that page manually from browser. Or create separate page that allows you to do that asynchronously. As you'll wish.

    from flask import Flask
    import subprocess
    
    app = Flask(__name__)
    script_proc = None
    src_path = '~/project/src/'
    
    
    def bash(cmd):
        subprocess.Popen(cmd)
    
    
    def pull_code(path):
        bash('git -C {path} reset --hard'.format(path=path))
        bash('git -C {path} clean -df'.format(path=path))
        bash('git -C {path} pull -f'.format(path=path))
        # or
        # If need just to copy files to remote machine:
        # (example of remote path "pi@192.168.1.1:~/project/src/")
        bash('scp -r {src_path} {dst_path}'.format(src_path=src_path, dst_path=path)) 
        
    
    
    def installation(python_path):
        bash('{python_path} -m pip install -r requirements.txt'.format(python_path=python_path))
    
    
    def stop_script():
        global script_proc
    
        if script_proc:
            script_proc.terminate()
    
    
    def start_script(python_path, script_path, args=None):
        global script_proc
    
        script_proc = subprocess.Popen(
            '{} {} {}'.format(str(python_path), script_path, ' '.join(args) or '')
        )
    
    
    @app.route('/deploy-webhook')
    def deploy_webhook():
        project_path = '~/project/some_project_path'
        script_path = 'script1.py'
        python_path = 'venv/bin/python'
    
        pull_code(project_path)
        installation(python_path)
    
        stop_script()
        start_script(python_path, script_path)
        return 'Deployed'