python 我的Docker Alpine LAMP的Docker控制台

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 我的Docker Alpine LAMP的Docker控制台相关的知识,希望对你有一定的参考价值。

#!/usr/bin/env python3

# TODO @ SL :: ask confirmation when removing sites or stopping server

import os
import sys
import shlex
import argparse
from subprocess import call, Popen, PIPE


APP_NAME = 'Docker Console'
APP_VERSION = '1.0'


CEND      = '\33[0m'
CBOLD     = '\33[1m'
CITALIC   = '\33[3m'
CURL      = '\33[4m'
CBLINK    = '\33[5m'
CBLINK2   = '\33[6m'
CSELECTED = '\33[7m'

CBLACK  = '\33[30m'
CRED    = '\33[31m'
CGREEN  = '\33[32m'
CYELLOW = '\33[33m'
CBLUE   = '\33[34m'
CVIOLET = '\33[35m'
CBEIGE  = '\33[36m'
CWHITE  = '\33[37m'

CBLACKBG  = '\33[40m'
CREDBG    = '\33[41m'
CGREENBG  = '\33[42m'
CYELLOWBG = '\33[43m'
CBLUEBG   = '\33[44m'
CVIOLETBG = '\33[45m'
CBEIGEBG  = '\33[46m'
CWHITEBG  = '\33[47m'

CGREY    = '\33[90m'
CRED2    = '\33[91m'
CGREEN2  = '\33[92m'
CYELLOW2 = '\33[93m'
CBLUE2   = '\33[94m'
CVIOLET2 = '\33[95m'
CBEIGE2  = '\33[96m'
CWHITE2  = '\33[97m'

CGREYBG    = '\33[100m'
CREDBG2    = '\33[101m'
CGREENBG2  = '\33[102m'
CYELLOWBG2 = '\33[103m'
CBLUEBG2   = '\33[104m'
CVIOLETBG2 = '\33[105m'
CBEIGEBG2  = '\33[106m'
CWHITEBG2  = '\33[107m'


# user = os.environ['USER']
user = os.getuid()

if os.path.islink(__file__):  # A symlink
    root_dir = os.readlink(__file__)[:-int(len(os.path.basename(__file__)))]  # Remove the filename to return the directory
else:   # Not a symlink
    root_dir = os.path.dirname(__file__)

vhosts_dir = os.path.join(root_dir, 'config', 'conf.d', 'vhosts')


def is_directory_valid():
    docker_compose_file_yml = os.path.join(root_dir, 'docker-compose.yml')
    docker_compose_file_yaml = os.path.join(root_dir, 'docker-compose.yaml')
    if not os.path.exists(docker_compose_file_yml) and not os.path.exists(docker_compose_file_yaml):
        print('Error: this script needs to be ran inside a directory with a `docker-compose.yml` or `docker-compose.yaml` file')
        exit(1)


class DockerConsole(object):

    # Init
    def __init__(self):
        parser = argparse.ArgumentParser(
            description='Do some server stuff (this script adds some functionality to my docker-compose lamp)',
            usage='''docker-console <command> [<subcommand>]

The command options are:
  %sserver%s    Start or stop the server
  %svhost%s     Add or remove a virtual host
''' % (CYELLOW, CEND, CYELLOW, CEND))
        parser.add_argument('command', type=str, help='"%sserver%s / %svhost%s"' % (CYELLOW, CEND, CYELLOW, CEND), nargs='?')
        args = parser.parse_args(sys.argv[1:2])
        if not args.command or not hasattr(self, args.command):
            print(CRED2 + 'Error: Unrecognized command\n' + CEND)
            parser.print_help()
            exit(1)
        getattr(self, args.command)()

    # Server
    def start(self):
        print(CYELLOW + 'Starting server...\n' + CEND)
        cmd = 'docker-compose up -d'
        p = Popen(shlex.split(cmd), stderr=PIPE, stdout=PIPE)

        output = p.communicate()
        if output[0]:  # stdout
            print(str(output[0], 'utf-8'))
        if output[1]:  # stderr
            print(str(output[1], 'utf-8'))

        # Check if need to chown
        config_dir = os.path.join(root_dir, 'config')
        html_dir = os.path.join(root_dir, 'html')

        if os.stat(config_dir).st_uid != user or os.stat(config_dir).st_gid != user:
            config_chown = True
        else:
            config_chown = False

        if os.stat(html_dir).st_uid != user or os.stat(html_dir).st_gid != user:
            html_chown = True
        else:
            html_chown = False

        if config_chown:
            cmd = 'sudo chown -R %s:%s ./config' % (user, user)
            p = call(shlex.split(cmd))

        if html_chown:
            cmd = 'sudo chown -R %s:%s ./html' % (user, user)
            p = call(shlex.split(cmd))

        print(CGREEN + 'Started server!' + CEND)

    def stop(self):
        print(CYELLOW + 'Stopping server...\n' + CEND)
        cmd = 'docker-compose stop'
        p = Popen(shlex.split(cmd), stderr=PIPE, stdout=PIPE)

        output = p.communicate()
        if output[0]:  # stdout
            print(str(output[0], 'utf-8'))
        if output[1]:  # stderr
            print(str(output[1], 'utf-8'))
        print(CGREEN + 'Stopped server!' + CEND)

    def restart(self):
        self.stop()
        self.start()

    def server(self):
        parser = argparse.ArgumentParser(
            description='Start or stop the server',
            usage='''docker-console server %s<option>%s

The server options are:
  %sstart%s     Start the server
  %sstop%s      Stop the server
  %srestart%s   Restart the server
''' % (CYELLOW, CEND, CYELLOW, CEND, CYELLOW, CEND, CYELLOW, CEND))
        parser.add_argument('option', type=str, help='"%sstart%s / %sstop%s / %srestart%s"' % (CYELLOW, CEND, CYELLOW, CEND, CYELLOW, CEND), nargs='?')
        args = parser.parse_args(sys.argv[2:])
        if not args.option or not hasattr(self, args.option):
            print(CRED2 + 'Error: Unrecognized subcommand\n' + CEND)
            parser.print_help()
            print('')
            exit(1)
        getattr(self, args.option)()

    # Vhost
    def list(self):
        print('Sites on this server: ')
        for i, site in enumerate(os.listdir(vhosts_dir)):
            print(CYELLOW + '  %s.' % str(i + 1) + CEND + ' %s' % site)

    def add(self):
        print('Add a site to this server:')
        print('\nUrl of the site:')
        site_name = input(' %s>%s ' % (CBEIGE, CEND))
        while not site_name.strip():
            site_name = input(' %s>%s ' % (CBEIGE, CEND))

        # TODO @ SL :: check if sitename already exists

        print('\nSite alias? [%swww%s] (type `%sno%s` for empty)' % (CGREEN, CEND, CYELLOW, CEND))
        site_alias = input(' %s>%s ' % (CBEIGE, CEND))
        if not site_alias.strip():
            site_alias = 'www'
        if site_alias.strip().lower() == 'www':
            site_alias = 'www'
        if site_alias.strip().lower() == 'no':
            site_alias = ''
        else:
            site_alias = site_alias.strip().lower()
        if site_alias:
            site_alias = site_alias + '.'

        print('\nPort of the site: [%s80%s]' % (CGREEN, CEND))
        site_port = input(' %s>%s ' % (CBEIGE, CEND))
        if not site_port.strip():
            site_port = '80'
        if site_port.strip() == 80:
            site_port = '80'
        if not site_port.strip().isnumeric():
            site_port = '80'
        else:
            site_port = str(site_port.strip())

        print('\nShould the public root be in the `%spublic%s` directory? [%sY%s/%sn%s]' % (CYELLOW, CEND, CGREEN, CEND, CRED2, CEND))
        public_dir = input(' %s>%s ' % (CBEIGE, CEND))
        if not public_dir.strip():
            public_dir = 'y'
        if public_dir.strip().lower() == 'y':
            public_dir = 'y'
        else:
            public_dir = 'n'

        # Confirmation
        print('\nPlease confirm to create the following site: [%sY%s/%sn%s]' % (CGREEN, CEND, CRED2, CEND))
        print('  Site url         %s: %s%s%s' % (CBLUE, CVIOLET, site_name, CEND))
        print('  Site alias       %s: %s%s%s' % (CBLUE, CVIOLET, site_alias, CEND))
        print('  Site port        %s: %s%s%s' % (CBLUE, CVIOLET, site_port, CEND))
        print('  Public directory %s: %s%s%s' % (CBLUE, CVIOLET, public_dir, CEND))
        confirm = input(' %s>%s ' % (CBEIGE, CEND))
        if not confirm.strip():
            confirm = 'y'
        if confirm.strip().lower() == 'y':
            confirm = 'y'
        else:
            confirm = 'n'
        if confirm == 'y':
            # Write file
            file = os.path.join(vhosts_dir, site_name + '.conf')
            fh = open(file, 'w')
            fh.write('<VirtualHost *:%s>\n' % str(site_port))
            fh.write('      ServerName %s\n' % site_name)
            fh.write('      ServerAlias %s%s\n\n' % (site_alias, site_name))
            if public_dir == 'y':
                fh.write('      DocumentRoot /web/html/%s/public\n' % site_name)
            else:
                fh.write('      DocumentRoot /web/html/%s\n' % site_name)
            fh.write('</VirtualHost>')
            fh.close()

            print(CGREEN + '\nAdded site: ' + site_name + CEND)
            print(CVIOLET + '\nTo be able to access this site, please restart the server' + CEND)

    def remove(self):
        print('Remove a site from this server:')
        print('\nType a name, or type `%slist%s` to choose from a list: ' % (CYELLOW, CEND))
        remove_input = input(' %s>%s ' % (CBEIGE, CEND))
        while not remove_input.strip():
            remove_input = input(' %s>%s ' % (CBEIGE, CEND))
        if remove_input.strip() == 'list':
            sites = {}
            for i, site in enumerate(os.listdir(vhosts_dir)):
                sites[str(i + 1)] = site
                print(CYELLOW + '  %s.' % str(i + 1) + CEND + ' %s' % site)
            print('\nRemove site number: ')
            site_number = input(' %s>%s ' % (CBEIGE, CEND))
            while not site_number.strip():
                site_number = input(' %s>%s ' % (CBEIGE, CEND))
            if site_number not in sites:
                print(CRED2 + '\nError: that site does not exist' + CEND)
                exit(1)

            file = os.path.join(vhosts_dir, sites[site_number])
            os.remove(file)  # TODO @ SL :: ask for confirmation first

            print(CGREEN + '\nRemoved site: ' + sites[site_number] + CEND)
        else:
            file = os.path.join(vhosts_dir, remove_input.strip() + '.conf')
            if not os.path.exists(file):
                print(CRED2 + '\nError: that site does not exist' + CEND)
                exit(1)

            os.remove(file)  # TODO @ SL :: ask for confirmation first

            print(CGREEN + '\nRemoved site: ' + remove_input.strip() + '.conf' + CEND)

    def vhost(self):
        if not os.path.exists(vhosts_dir):
            os.mkdir(vhosts_dir)
        parser = argparse.ArgumentParser(
            description='Add or remove a virtual host',
            usage='''docker-console vhost %s<option>%s

The vhost options are:
  %slist%s      List all virtual hosts
  %sadd%s       Add a virtual host
  %sremove%s    Remove a virtual host
''' % (CYELLOW, CEND, CYELLOW, CEND, CYELLOW, CEND, CYELLOW, CEND))
        parser.add_argument('option', type=str, help='"%slist%s / %sadd%s / %sremove%s"' % (CYELLOW, CEND, CYELLOW, CEND, CYELLOW, CEND), nargs='?')
        args = parser.parse_args(sys.argv[2:])
        if not args.option or not hasattr(self, args.option):
            print(CRED2 + 'Error: Unrecognized subcommand\n' + CEND)
            parser.print_help()
            print('')
            exit(1)
        getattr(self, args.option)()


if __name__ == '__main__':
    print('\n' + CBEIGE + '[ ' + CVIOLET + APP_NAME + CBLUE + ' v' + APP_VERSION + CBEIGE + ' ]' + CEND + '\n')

    # Check if there is a docker-compose file in this directory.
    is_directory_valid()

    try:
        DockerConsole()
    except KeyboardInterrupt:
        print('\n')
        sys.exit(0)

    print('')

以上是关于python 我的Docker Alpine LAMP的Docker控制台的主要内容,如果未能解决你的问题,请参考以下文章

Alpine makes Python Docker builds 50× slower, and images 2× larger

将 bcrypt 添加到 package.json 时,如何使用 docker node alpine Image 解决“找不到任何要使用的 Python 安装”?

docker在alpine linux中构建python django应用程序时出错

Sanic over alpine:latest(3.9) 的 Docker 镜像使用 python json 而不是 ujson

「容器架构」Debian和 Alpine作为基准Docker映像的对比

Docker Alpine:加载 MySQLdb 模块时出错