comparison piecrust/commands/builtin/admin.py @ 886:dcdec4b951a1

admin: Get the admin panel working again.
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 20 Jun 2017 21:13:08 -0700
parents 4850f8c21b6e
children 33a89139c284
comparison
equal deleted inserted replaced
885:13e8b50a2113 886:dcdec4b951a1
1 import os 1 import os
2 import os.path 2 import os.path
3 import logging 3 import logging
4 from piecrust import CACHE_DIR 4 from piecrust import CACHE_DIR, CONFIG_PATH
5 from piecrust.commands.base import ChefCommand 5 from piecrust.commands.base import ChefCommand
6 from piecrust.pathutil import SiteNotFoundError 6 from piecrust.pathutil import SiteNotFoundError
7 7
8 8
9 logger = logging.getLogger(__name__) 9 logger = logging.getLogger(__name__)
20 subparsers = parser.add_subparsers() 20 subparsers = parser.add_subparsers()
21 21
22 p = subparsers.add_parser( 22 p = subparsers.add_parser(
23 'init', 23 'init',
24 help="Creates a new administration panel website.") 24 help="Creates a new administration panel website.")
25 p.set_defaults(sub_func=self._initFoodTruck) 25 p.set_defaults(sub_func=self._initAdminSite)
26 26
27 p = subparsers.add_parser( 27 p = subparsers.add_parser(
28 'genpass', 28 'genpass',
29 help=("Generates the hashed password for use as an " 29 help=("Generates the hashed password for use as an "
30 "admin password")) 30 "admin password"))
45 p.add_argument( 45 p.add_argument(
46 '--no-assets', 46 '--no-assets',
47 help="Don't process and monitor the asset folder(s).", 47 help="Don't process and monitor the asset folder(s).",
48 dest='monitor_assets', 48 dest='monitor_assets',
49 action='store_false') 49 action='store_false')
50 p.set_defaults(sub_func=self._runFoodTruck) 50 p.add_argument(
51 '--use-reloader',
52 help="Restart the server when PieCrust code changes",
53 action='store_true')
54 p.add_argument(
55 '--use-debugger',
56 help="Show the debugger when an error occurs",
57 action='store_true')
58 p.set_defaults(sub_func=self._runAdminSite)
51 59
52 def checkedRun(self, ctx): 60 def checkedRun(self, ctx):
53 if ctx.app.root_dir is None: 61 if ctx.app.root_dir is None:
54 raise SiteNotFoundError(theme=ctx.app.theme_site) 62 raise SiteNotFoundError(theme=ctx.app.theme_site)
55 63
56 if not hasattr(ctx.args, 'sub_func'): 64 if not hasattr(ctx.args, 'sub_func'):
57 ctx.parser.parse_args(['admin', '--help']) 65 ctx.parser.parse_args(['admin', '--help'])
58 return 66 return
59 return ctx.args.sub_func(ctx) 67 return ctx.args.sub_func(ctx)
60 68
61 def _runFoodTruck(self, ctx): 69 def _runAdminSite(self, ctx):
62 # See `_run_sse_check` in `piecrust.serving.wrappers` for an 70 # See `_run_sse_check` in `piecrust.serving.wrappers` for an
63 # explanation of this check. 71 # explanation of this check.
64 if (ctx.args.monitor_assets and ( 72 if (ctx.args.monitor_assets and (
65 not ctx.args.debug or 73 not (ctx.args.debug or ctx.args.use_reloader) or
66 os.environ.get('WERKZEUG_RUN_MAIN') == 'true')): 74 os.environ.get('WERKZEUG_RUN_MAIN') == 'true')):
67 from piecrust.serving.procloop import ProcessingLoop 75 from piecrust.serving.procloop import ProcessingLoop
68 out_dir = os.path.join( 76 out_dir = os.path.join(
69 ctx.app.root_dir, CACHE_DIR, 'foodtruck', 'server') 77 ctx.app.root_dir, CACHE_DIR, 'admin', 'server')
70 proc_loop = ProcessingLoop(ctx.appfactory, out_dir) 78 proc_loop = ProcessingLoop(ctx.appfactory, out_dir)
71 proc_loop.start() 79 proc_loop.start()
72 80
73 es = { 81 es = {
74 'FOODTRUCK_CMDLINE_MODE': True, 82 'FOODTRUCK_CMDLINE_MODE': True,
75 'FOODTRUCK_ROOT': ctx.app.root_dir} 83 'FOODTRUCK_ROOT': ctx.app.root_dir,
76 from piecrust.admin.main import run_foodtruck 84 'FOODTRUCK_URL_PREFIX': '',
85 'SECRET_KEY': os.urandom(22),
86 'LOGIN_DISABLED': True}
87 if ctx.args.debug or ctx.args.use_debugger:
88 es['DEBUG'] = True
89
77 run_foodtruck( 90 run_foodtruck(
78 host=ctx.args.address, 91 host=ctx.args.address,
79 port=ctx.args.port, 92 port=ctx.args.port,
80 debug=ctx.args.debug, 93 use_reloader=ctx.args.use_reloader,
81 extra_settings=es) 94 extra_settings=es)
82 95
83 def _initFoodTruck(self, ctx): 96 def _initAdminSite(self, ctx):
97 import io
84 import getpass 98 import getpass
85 from piecrust.admin import bcryptfallback as bcrypt 99 from piecrust.admin import bcryptfallback as bcrypt
86 100
87 secret_key = os.urandom(22) 101 secret_key = os.urandom(22)
88 admin_username = input("Admin username (admin): ") or 'admin' 102 admin_username = input("Admin username (admin): ") or 'admin'
89 admin_password = getpass.getpass("Admin password: ") 103 admin_password = getpass.getpass("Admin password: ")
90 if not admin_password: 104 if not admin_password:
91 logger.warning("No administration password set!") 105 logger.warning("No administration password set!")
92 logger.warning("Don't make this instance of FoodTruck public.") 106 logger.warning("Don't make this instance of the PieCrust "
107 "administration panel public.")
93 logger.info("You can later set an admin password by editing " 108 logger.info("You can later set an admin password by editing "
94 "the `foodtruck.yml` file and using the " 109 "the `admin.cfg` file and using the "
95 "`chef admin genpass` command.") 110 "`chef admin genpass` command.")
96 else: 111 else:
97 binpw = admin_password.encode('utf8') 112 binpw = admin_password.encode('utf8')
98 hashpw = bcrypt.hashpw(binpw, bcrypt.gensalt()).decode('utf8') 113 hashpw = bcrypt.hashpw(binpw, bcrypt.gensalt()).decode('utf8')
99 admin_password = hashpw 114 admin_password = hashpw
100 115
101 ft_config = """ 116 ft_config = """
102 security: 117 admin:
118 secret_key: %(secret_key)s
103 username: %(username)s 119 username: %(username)s
104 # You can generate another hashed password with `chef admin genpass`. 120 # You can generate another hashed password with `chef admin genpass`.
105 password: %(password)s 121 password: %(password)s
106 """ 122 """
107 ft_config = ft_config % { 123 ft_config = ft_config % {
124 'secret_key': secret_key,
108 'username': admin_username, 125 'username': admin_username,
109 'password': admin_password 126 'password': admin_password
110 } 127 }
111 with open('foodtruck.yml', 'w', encoding='utf8') as fp: 128
129 config_path = os.path.join(ctx.app.root_dir, CONFIG_PATH)
130 with open(config_path, 'a+', encoding='utf8') as fp:
131 fp.seek(0, io.SEEK_END)
132 fp.write('\n')
112 fp.write(ft_config) 133 fp.write(ft_config)
113
114 flask_config = """
115 SECRET_KEY = %(secret_key)s
116 """
117 flask_config = flask_config % {'secret_key': secret_key}
118 with open('app.cfg', 'w', encoding='utf8') as fp:
119 fp.write(flask_config)
120 134
121 def _generatePassword(self, ctx): 135 def _generatePassword(self, ctx):
122 from piecrust.admin import bcryptfallback as bcrypt 136 from piecrust.admin import bcryptfallback as bcrypt
123 binpw = ctx.args.password.encode('utf8') 137 binpw = ctx.args.password.encode('utf8')
124 hashpw = bcrypt.hashpw(binpw, bcrypt.gensalt()).decode('utf8') 138 hashpw = bcrypt.hashpw(binpw, bcrypt.gensalt()).decode('utf8')
125 logger.info(hashpw) 139 logger.info(hashpw)
126 140
141
142 def run_foodtruck(host=None, port=None, use_reloader=False,
143 extra_settings=None):
144 es = {}
145 if extra_settings:
146 es.update(extra_settings)
147
148 # Disable PIN protection with Werkzeug's debugger.
149 os.environ['WERKZEUG_DEBUG_PIN'] = 'off'
150
151 try:
152 from piecrust.admin.web import create_foodtruck_app
153 app = create_foodtruck_app(es)
154 app.run(host=host, port=port, use_reloader=use_reloader,
155 threaded=True)
156 except SystemExit:
157 # This is needed for Werkzeug's code reloader to be able to correctly
158 # shutdown the child process in order to restart it (otherwise, SSE
159 # generators will keep it alive).
160 try:
161 from . import pubutil
162 logger.debug("Shutting down SSE generators from main...")
163 pubutil.server_shutdown = True
164 except ImportError:
165 pass
166 raise
167