LoginSignup
2
5

More than 1 year has passed since last update.

Flaskでラズパイの状態を確認するWebアプリを作ってみた(其の一)

Posted at

ラズパイの状態診断サイトを作ってみる

top_page.png

ユースケース

  • subprocessモジュールでLinuxの各種コマンドを実行し結果をWebスタイルで表示
  • コマンドの実行結果をそのまま再現(可能な限り)

実行Linuxコマンド

コマンド 内容
ip addr インターフェースのIPアドレス
ss ソケット
route ルーティングテーブル
vcgencmd ラズパイ SoC温度
lsblk & df ディスク情報(ブロックとディレクトリ毎の容量)

ファイル & ディレクトリ

webapp 
  ├─ static
  |    ├─ css
  |    |   └─ style.css
  |    ├─ images
  |    |   └─ raspi-logo.png
  |    └─ temp
  |        ├─ get_disk.txt
  |        ├─ get_ip_addr.txt
  |        ├─ get_route.txt
  |        └─ get_socket.txt
  ├─ templates
  |      ├─ get_disk.html
  |      ├─ get_ip_addr.html
  |      ├─ get_route.html
  |      ├─ get_socket.html
  |      ├─ get_temp.html
  |      └─ index.html
  └─ webapp.py

Flask コード

デコレータ以外のコード

webapp.py
import subprocess
import re
from flask import Flask, render_template, url_for, redirect, session, request

# Running up a instance as webapp
webapp = Flask(__name__)

~
@webapp.route()         # => 別途記載 : 省略
~

# Debug mode on
if __name__ == ('__main__'):
    webapp.run(debug = True)

webapp.png


トップページ

webapp.py
# TopPage
@webapp.route('/')
def index():
    main_content = 'Diagnosis of Raspberry Pi'
    return render_template('index.html', main_content=main_content)
index.html
<!--- "main"部分のみ記載 --->
    <div class="main">
        <h2> {{main_content}} </h2>
        <ul>
            <h3><a href="{{ url_for('get_ip_addr') }}">Interface IP Address</a></h3>
            <h3><a href="{{ url_for('get_socket') }}">Socket</a></h3>
            <h3><a href="{{ url_for('get_route') }}">IP Routing Table</a></h3>
            <h3><a href="{{ url_for('get_temp') }}">Temparature</a></h3>
            <h3><a href="{{ url_for('get_disk') }}">Disk Usage</a></h3>
        </ul>
    </div>

IPアドレス

ip_address.png

webapp.py
#Get IP address via "ip -4 address" command
@webapp.route('/get_ip_addr')
def get_ip_addr():
    ipv4_addrs = subprocess.run(['ip', '-4', 'address'],
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
    ipv4_addrs_result = ipv4_addrs.stdout.decode('utf-8')

    with open('/WebApp/static/temp/get_ip_addr.txt', 'w') as f:
        f.write(ipv4_addrs_result)

    result_list = []

    with open('/WebApp/static/temp/get_ip_addr.txt', 'r') as f:
        for line in f:
            if re.search('^\s*inet', line):
                line0 = line.lstrip(' ').rstrip('\n').split()
                result_list.append(line0)

    result_list1 = []

    for result in result_list:
        result_list1.append((result[-1], result[1]))

    result_dict = dict(result_list1)

    return render_template('get_ip_addr.html', result=result_dict)
get_ip_addr.html
<!--- "main"部分のみ記載 --->
    <div class="main">
        <h2>Interface IP Address</h2>
        <ul>
            {% for if, addr in result.items()%}
            <h4>
                <li>{{ if }} : {{ addr }}</li>
            </h4>
            {% endfor %}
        </ul>
    </div>

ソケット

socket.png

webapp.py
#Get Socket info via "ss -tu" command
@webapp.route('/get_socket')
def get_socket():
    get_socket = subprocess.run(['ss', '-tu'],
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
    cmd_result = get_socket.stdout.decode('utf-8')

    with open('/WebApp/static/temp/get_socket.txt', 'w') as f:
        f.write(cmd_result)

    socket_list = []

    with open('/WebApp/static/temp/get_socket.txt', 'r') as f:
        for read_line in f:
            txt_value0 = re.sub(r'\s+', ',', read_line)
            txt_value1 = txt_value0.split(',')
            socket_list.append(txt_value1)

    socket_list1 = []

    for list_value in socket_list:
        socket_list1.append(list_value)

        if 'Netid' in list_value:
            value0 = list_value[4] + '-' + list_value[5]
            value1 = list_value[6] + '-' + list_value[7]
            socket_list1[0].insert(4, value0)
            socket_list1[0].insert(5, value1)
            socket_list1[0].remove('Local')
            socket_list1[0].remove('Peer')
            socket_list1[0].remove('Address:Port')
            socket_list1[0].remove('Address:Port')
            del socket_list1[0][-1]

    return render_template('get_socket.html', result=socket_list1)
get_socket.html
<!--- "main"部分のみ記載 --->
    <div class="main">
        <h2>Socket</h2>
        <div class="main-list">
            <ul>
            <table>
                <thead>
                    <tr>
                        <div class="main-list">
                        <th colspan="7">Socket Table</th>
                        </div>
                    </tr>
                </thead>
                <tbody>
                    {% for i in result %}
                    <tr>
                        <div class="main-list">
                        <td>{{ i[0] }}</td>
                        <td>{{ i[1] }}</td>
                        <td>{{ i[2] }}</td>
                        <td>{{ i[3] }}</td>
                        <td>{{ i[4] }}</td>
                        <td>{{ i[5] }}</td>
                        <td>{{ i[6] }}</td>
                        </div>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
            </ul>
        </div>
    </div>

ルーティングテーブル

ip_routing.png

webapp.py
# Get IP routing table via "route" command
@webapp.route('/get_route')
def get_route():
    get_route_table = subprocess.run(['route'],
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
    func_result = get_route_table.stdout.decode('utf-8')

    with open('/WebApp/static/temp/get_route.txt', 'w') as f:
        f.write(func_result)

    route_table = []

    with open('/WebApp/static/temp/get_route.txt', 'r') as f:
        for read_line in f:
            txt_value = read_line.split()
            route_table.append(txt_value)

    del route_table[0]

    return render_template('get_route.html', result=route_table)
get_route.html
<!--- "main"部分のみ記載 --->
    <div class="main">
        <h2>IP Routing Table</h2>
        <div class="main-list">
            <ul>
                <table>
                    <thead>
                        <tr>
                            <div class="main-list">
                                <th colspan="8">Routing Table</th>
                            </div>
                        </tr>
                    </thead>
                    <tbody>
                        {% for i in result %}
                        <tr>
                            <div class="main-list">
                                <td>{{ i[0] }}</td>
                                <td>{{ i[1] }}</td>
                                <td>{{ i[2] }}</td>
                                <td>{{ i[3] }}</td>
                                <td>{{ i[4] }}</td>
                                <td>{{ i[5] }}</td>
                                <td>{{ i[6] }}</td>
                                <td>{{ i[7] }}</td>
                            </div>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </ul>
        </div>
    </div>

温度

temparature.png

get_temp.py
#Get SoC temparature via "vcgencmd measure_temp" command
@webapp.route('/get_temp')
def get_temp():
    get_temp = subprocess.run(['vcgencmd', 'measure_temp'],
                            stdout = subprocess.PIPE,
                            stderr=subprocess.PIPE)
    value0 = get_temp.stdout.decode('utf-8')
    value1 = value0.split('=')
    value2 = value1[1][:-2]
    cmd_result = f'SoC Temparature : { value2 }C \n'

    return render_template('get_temp.html', result=cmd_result)
get_temp.html
<!--- "main"部分のみ記載 --->
    <div class="main">
        <h2>SoC Temparature</h2>
        <ul>
            <h4>
                <li><h3>{{result}}</h3></li>
            </h4>
        </ul>
    </div>

ディスク容量

disk_new.png

webapp.py
#Get disk info via "lsbk" & "df -h" command
@webapp.route('/get_disk')
def get_disk():

    #Get disk info via "lsblk" command
    get_block_dev = subprocess.run(['lsblk'],
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
    lsblk_result = get_block_dev.stdout.decode('utf-8')

    with open('/WebApp/static/temp/get_lsblk.txt', 'w') as f:
        f.write(lsblk_result)

    result_list0 = []

    with open('/WebApp/static/temp/get_lsblk.txt', 'r') as f:
        for line in f:
            line0 = line.rstrip('\n').split()
            result_list0.append(line0)

    #Get disk info via "df -h" command
    get_disk_usage = subprocess.run(['df', '-h'],
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
    df_result = get_disk_usage.stdout.decode('utf-8')

    with open('/WebApp/static/temp/get_df.txt', 'w') as f:
        f.write(df_result)

    result_list1 = []

    with open('/WebApp/static/temp/get_df.txt', 'r') as f:
        for line in f:
            line0 = line.rstrip('\n').split()
            result_list1.append(line0)

    result_list2 = []

    for line in result_list1:
        result_list2.append(line)

        if 'Filesystem' in line:
            h_list = line[5] + '-' + line[6]
            result_list2[0].insert(5, h_list)
            result_list2[0].remove('Mounted')
            result_list2[0].remove('on')

    return render_template('get_disk.html', lsblk_result=result_list0, 
                            df_result=result_list2)
get_disk.html
<!--- "main"部分のみ記載 --->
    <div class="main">
        <h2>Storage Capacity</h2>
    
        <h4>Block Device</h4>
        <div class="main-list">
            <ul>
                <table>
                    <thead>
                        <tr>
                            <div class="main-list">
                                <th colspan="7">Block Device</th>
                            </div>
                        </tr>
                    </thead>
                    <tbody>
                        {% for i in lsblk_result %}
                        <tr>
                            <div class="main-list">
                                <td>{{ i[0] }}</td>
                                <td>{{ i[1] }}</td>
                                <td>{{ i[2] }}</td>
                                <td>{{ i[3] }}</td>
                                <td>{{ i[4] }}</td>
                                <td>{{ i[5] }}</td>
                                <td>{{ i[6] }}</td>
                            </div>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </ul>
        </div>

        <h4>Disk Usage</h4>
        <div class="main-list">
            <ul>
                <table>
                    <thead>
                        <tr>
                            <div class="main-list">
                                <th colspan="6">Disk Usage</th>
                            </div>
                        </tr>
                    </thead>
                    <tbody>
                        {% for i in df_result %}
                        <tr>
                            <div class="main-list">
                                <td>{{ i[0] }}</td>
                                <td>{{ i[1] }}</td>
                                <td>{{ i[2] }}</td>
                                <td>{{ i[3] }}</td>
                                <td>{{ i[4] }}</td>
                                <td>{{ i[5] }}</td>
                            </div>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </ul>
        </div>
    </div>

ラズパイのブランドガイドライン

Raspberry Pi trademark rules and brand guidelines

  • 上記ガイドラインを遵守してロゴなどを使わせていただきました。
    ※ロゴイメージからラズパイサイトへのリンクもちゃんと貼っています。(記載ないけど)

まとめ

  • とりあえず、第一段階としてコマンド実行の結果を表示するところまで作ってみた。
  • 今後やること
    • HTML、CSSの見直し/ブラッシュアップ
    • 実装したいことのロードマップを作る?
      • Nginx、uWSGI上でのアプリ展開
      • 対応コマンドの数を増やす
      • HTMLテンプレートの継承
      • ユーザー認証、DB連携など
      • なにか楽しそうなもの 😄✨
2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5