arches_extensions.management.commands.configure
1import sys 2from pathlib import Path 3from django.core.management.base import BaseCommand 4 5from arches_extensions.utils import user_confirms 6class Command(BaseCommand): 7 """ 8 Configure service files used for Arches. Using this command will derive 9 information about your app and python environment and write these directly 10 into the files. 11 12 Usage: 13 14 python manage.py configure [operation] 15 16 Operations: 17 18 - `celery` 19 20 """ 21 22 def __init__(self, *args, **kwargs): 23 self.help = self.__doc__ 24 25 def add_arguments(self, parser): 26 27 parser.add_argument( 28 "operation", 29 choices=["celery"] 30 ) 31 parser.add_argument( 32 "-a", "--app", 33 help="Name of the Celery app your project creates (see celery.py)." 34 ) 35 parser.add_argument( 36 "-d", "--destination", 37 default=".services", 38 help="Optional path for output. Defaults to .services/ in root directory." 39 ) 40 parser.add_argument( 41 "--log-dir", 42 default=".logs", 43 help="Path to where logs and pid files will go. Defaults to .logs in root directory." 44 ) 45 parser.add_argument( 46 "--log-level", 47 default="DEBUG", 48 choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'FATAL'], 49 help="Set log level for celery. Default is DEBUG." 50 ) 51 parser.add_argument( 52 "--prefix", 53 help="Optional prefix for the names of the services to be written." 54 ) 55 parser.add_argument( 56 "--require-rabbitmq", 57 action="store_true", 58 default=False, 59 help="If true, Celery services will require rabbitmq.service", 60 ) 61 62 def handle(self, *args, **options): 63 64 self.dest = Path(options["destination"]).resolve() 65 self.dest.mkdir(exist_ok=True) 66 67 self.log_dir = Path(options["log_dir"]).resolve() 68 self.log_dir.mkdir(exist_ok=True) 69 70 python_env = Path(sys.executable).parent.parent 71 self.celery_bin = Path(python_env, "bin", "celery") 72 73 self.working_directory = Path(".").resolve() 74 75 if options["operation"] == "celery": 76 app = options["app"] 77 if not app: 78 print("-a/--app is require for celery configuration. cancelling.") 79 exit() 80 self.write_celery_services( 81 options["app"], 82 prefix=options["prefix"], 83 log_level=options["log_level"], 84 require_rabbitmq=options["require_rabbitmq"], 85 ) 86 87 def write_celery_services(self, app_name, prefix=None, log_level="DEBUG", require_rabbitmq=False): 88 89 requirement_block = "After=network.target" 90 if user_confirms("Configure rabbitmq-server as a dependency? "/ 91 "Do this if rabbitmq runs locally as a systemd service."): 92 requirement_block = "After=rabbitmq-server.service\nRequires=rabbitmq-server.service" 93 94 prefix_ = "" if not prefix else f"{prefix}_" 95 main_fname = f"{prefix_}celery.service" 96 main_full_path = Path(self.dest, main_fname) 97 98 with open(main_full_path, "w") as o: 99 o.write(f"""[Unit] 100Description=Celery Service{f" ({prefix})" if prefix else ""} 101{requirement_block} 102 103[Service] 104Type=simple 105WorkingDirectory={self.working_directory} 106ExecStart=/bin/sh -c '{self.celery_bin} \\ 107 -A {app_name} worker -n worker1@%h \\ 108 -B \\ 109 -s celerybeat-schedule \\ 110 --pidfile={self.log_dir}/{prefix_}celery.pid \\ 111 --logfile={self.log_dir}/{prefix_}celery.log \\ 112 --loglevel={log_level}' 113ExecStop=/bin/sh -c '{self.celery_bin} worker stopwait \\ 114 --pidfile={self.log_dir}/{prefix_}celery.pid \\ 115 --logfile={self.log_dir}/{prefix_}celery.log \\ 116 --loglevel={log_level}' 117Restart=always 118RestartSec=1 119 120[Install] 121WantedBy=multi-user.target 122""") 123 124 beat_fname = f"{prefix_}celerybeat.service" 125 beat_full_path = Path(self.dest, beat_fname) 126 with open(beat_full_path, "w") as o: 127 o.write(f"""[Unit] 128Description=Celery Beat Service{f" ({prefix})" if prefix else ""} 129After=network.target 130 131[Service] 132Type=simple 133WorkingDirectory={self.working_directory} 134ExecStart=/bin/sh -c '{self.celery_bin} \\ 135 -A {app_name} beat \\ 136 --pidfile={self.log_dir}/{prefix_}celerybeat.pid \\ 137 --logfile={self.log_dir}/{prefix_}celerybeat.log \\ 138 --loglevel={log_level}' 139Restart=always 140RestartSec=1 141 142[Install] 143WantedBy=multi-user.target 144""") 145 146 print(f""" 147Service files written to: {self.dest.relative_to(self.working_directory)}. 148Logs written to: {self.log_dir.relative_to(self.working_directory)}. 149 150*Make sure these directories are gitignored!* 151 152Initial deployment (first time only): 153 sudo ln -sf {main_full_path.absolute()} /etc/systemd/system/ 154 sudo ln -sf {beat_full_path.absolute()} /etc/systemd/system/ 155 sudo systemctl enable celery 156 sudo systemctl enable celerybeat 157 sudo systemctl start celery 158 sudo systemctl start celery 159 160Reload services: 161 sudo systemctl daemon-reload 162 sudo systemctl restart celery 163 sudo systemctl restart celerybeat 164""")
class
Command(django.core.management.base.BaseCommand):
7class Command(BaseCommand): 8 """ 9 Configure service files used for Arches. Using this command will derive 10 information about your app and python environment and write these directly 11 into the files. 12 13 Usage: 14 15 python manage.py configure [operation] 16 17 Operations: 18 19 - `celery` 20 21 """ 22 23 def __init__(self, *args, **kwargs): 24 self.help = self.__doc__ 25 26 def add_arguments(self, parser): 27 28 parser.add_argument( 29 "operation", 30 choices=["celery"] 31 ) 32 parser.add_argument( 33 "-a", "--app", 34 help="Name of the Celery app your project creates (see celery.py)." 35 ) 36 parser.add_argument( 37 "-d", "--destination", 38 default=".services", 39 help="Optional path for output. Defaults to .services/ in root directory." 40 ) 41 parser.add_argument( 42 "--log-dir", 43 default=".logs", 44 help="Path to where logs and pid files will go. Defaults to .logs in root directory." 45 ) 46 parser.add_argument( 47 "--log-level", 48 default="DEBUG", 49 choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'FATAL'], 50 help="Set log level for celery. Default is DEBUG." 51 ) 52 parser.add_argument( 53 "--prefix", 54 help="Optional prefix for the names of the services to be written." 55 ) 56 parser.add_argument( 57 "--require-rabbitmq", 58 action="store_true", 59 default=False, 60 help="If true, Celery services will require rabbitmq.service", 61 ) 62 63 def handle(self, *args, **options): 64 65 self.dest = Path(options["destination"]).resolve() 66 self.dest.mkdir(exist_ok=True) 67 68 self.log_dir = Path(options["log_dir"]).resolve() 69 self.log_dir.mkdir(exist_ok=True) 70 71 python_env = Path(sys.executable).parent.parent 72 self.celery_bin = Path(python_env, "bin", "celery") 73 74 self.working_directory = Path(".").resolve() 75 76 if options["operation"] == "celery": 77 app = options["app"] 78 if not app: 79 print("-a/--app is require for celery configuration. cancelling.") 80 exit() 81 self.write_celery_services( 82 options["app"], 83 prefix=options["prefix"], 84 log_level=options["log_level"], 85 require_rabbitmq=options["require_rabbitmq"], 86 ) 87 88 def write_celery_services(self, app_name, prefix=None, log_level="DEBUG", require_rabbitmq=False): 89 90 requirement_block = "After=network.target" 91 if user_confirms("Configure rabbitmq-server as a dependency? "/ 92 "Do this if rabbitmq runs locally as a systemd service."): 93 requirement_block = "After=rabbitmq-server.service\nRequires=rabbitmq-server.service" 94 95 prefix_ = "" if not prefix else f"{prefix}_" 96 main_fname = f"{prefix_}celery.service" 97 main_full_path = Path(self.dest, main_fname) 98 99 with open(main_full_path, "w") as o: 100 o.write(f"""[Unit] 101Description=Celery Service{f" ({prefix})" if prefix else ""} 102{requirement_block} 103 104[Service] 105Type=simple 106WorkingDirectory={self.working_directory} 107ExecStart=/bin/sh -c '{self.celery_bin} \\ 108 -A {app_name} worker -n worker1@%h \\ 109 -B \\ 110 -s celerybeat-schedule \\ 111 --pidfile={self.log_dir}/{prefix_}celery.pid \\ 112 --logfile={self.log_dir}/{prefix_}celery.log \\ 113 --loglevel={log_level}' 114ExecStop=/bin/sh -c '{self.celery_bin} worker stopwait \\ 115 --pidfile={self.log_dir}/{prefix_}celery.pid \\ 116 --logfile={self.log_dir}/{prefix_}celery.log \\ 117 --loglevel={log_level}' 118Restart=always 119RestartSec=1 120 121[Install] 122WantedBy=multi-user.target 123""") 124 125 beat_fname = f"{prefix_}celerybeat.service" 126 beat_full_path = Path(self.dest, beat_fname) 127 with open(beat_full_path, "w") as o: 128 o.write(f"""[Unit] 129Description=Celery Beat Service{f" ({prefix})" if prefix else ""} 130After=network.target 131 132[Service] 133Type=simple 134WorkingDirectory={self.working_directory} 135ExecStart=/bin/sh -c '{self.celery_bin} \\ 136 -A {app_name} beat \\ 137 --pidfile={self.log_dir}/{prefix_}celerybeat.pid \\ 138 --logfile={self.log_dir}/{prefix_}celerybeat.log \\ 139 --loglevel={log_level}' 140Restart=always 141RestartSec=1 142 143[Install] 144WantedBy=multi-user.target 145""") 146 147 print(f""" 148Service files written to: {self.dest.relative_to(self.working_directory)}. 149Logs written to: {self.log_dir.relative_to(self.working_directory)}. 150 151*Make sure these directories are gitignored!* 152 153Initial deployment (first time only): 154 sudo ln -sf {main_full_path.absolute()} /etc/systemd/system/ 155 sudo ln -sf {beat_full_path.absolute()} /etc/systemd/system/ 156 sudo systemctl enable celery 157 sudo systemctl enable celerybeat 158 sudo systemctl start celery 159 sudo systemctl start celery 160 161Reload services: 162 sudo systemctl daemon-reload 163 sudo systemctl restart celery 164 sudo systemctl restart celerybeat 165""")
Configure service files used for Arches. Using this command will derive information about your app and python environment and write these directly into the files.
Usage:
python manage.py configure [operation]
Operations:
- `celery`
def
add_arguments(self, parser):
26 def add_arguments(self, parser): 27 28 parser.add_argument( 29 "operation", 30 choices=["celery"] 31 ) 32 parser.add_argument( 33 "-a", "--app", 34 help="Name of the Celery app your project creates (see celery.py)." 35 ) 36 parser.add_argument( 37 "-d", "--destination", 38 default=".services", 39 help="Optional path for output. Defaults to .services/ in root directory." 40 ) 41 parser.add_argument( 42 "--log-dir", 43 default=".logs", 44 help="Path to where logs and pid files will go. Defaults to .logs in root directory." 45 ) 46 parser.add_argument( 47 "--log-level", 48 default="DEBUG", 49 choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'FATAL'], 50 help="Set log level for celery. Default is DEBUG." 51 ) 52 parser.add_argument( 53 "--prefix", 54 help="Optional prefix for the names of the services to be written." 55 ) 56 parser.add_argument( 57 "--require-rabbitmq", 58 action="store_true", 59 default=False, 60 help="If true, Celery services will require rabbitmq.service", 61 )
Entry point for subclassed commands to add custom arguments.
def
handle(self, *args, **options):
63 def handle(self, *args, **options): 64 65 self.dest = Path(options["destination"]).resolve() 66 self.dest.mkdir(exist_ok=True) 67 68 self.log_dir = Path(options["log_dir"]).resolve() 69 self.log_dir.mkdir(exist_ok=True) 70 71 python_env = Path(sys.executable).parent.parent 72 self.celery_bin = Path(python_env, "bin", "celery") 73 74 self.working_directory = Path(".").resolve() 75 76 if options["operation"] == "celery": 77 app = options["app"] 78 if not app: 79 print("-a/--app is require for celery configuration. cancelling.") 80 exit() 81 self.write_celery_services( 82 options["app"], 83 prefix=options["prefix"], 84 log_level=options["log_level"], 85 require_rabbitmq=options["require_rabbitmq"], 86 )
The actual logic of the command. Subclasses must implement this method.
def
write_celery_services( self, app_name, prefix=None, log_level='DEBUG', require_rabbitmq=False):
88 def write_celery_services(self, app_name, prefix=None, log_level="DEBUG", require_rabbitmq=False): 89 90 requirement_block = "After=network.target" 91 if user_confirms("Configure rabbitmq-server as a dependency? "/ 92 "Do this if rabbitmq runs locally as a systemd service."): 93 requirement_block = "After=rabbitmq-server.service\nRequires=rabbitmq-server.service" 94 95 prefix_ = "" if not prefix else f"{prefix}_" 96 main_fname = f"{prefix_}celery.service" 97 main_full_path = Path(self.dest, main_fname) 98 99 with open(main_full_path, "w") as o: 100 o.write(f"""[Unit] 101Description=Celery Service{f" ({prefix})" if prefix else ""} 102{requirement_block} 103 104[Service] 105Type=simple 106WorkingDirectory={self.working_directory} 107ExecStart=/bin/sh -c '{self.celery_bin} \\ 108 -A {app_name} worker -n worker1@%h \\ 109 -B \\ 110 -s celerybeat-schedule \\ 111 --pidfile={self.log_dir}/{prefix_}celery.pid \\ 112 --logfile={self.log_dir}/{prefix_}celery.log \\ 113 --loglevel={log_level}' 114ExecStop=/bin/sh -c '{self.celery_bin} worker stopwait \\ 115 --pidfile={self.log_dir}/{prefix_}celery.pid \\ 116 --logfile={self.log_dir}/{prefix_}celery.log \\ 117 --loglevel={log_level}' 118Restart=always 119RestartSec=1 120 121[Install] 122WantedBy=multi-user.target 123""") 124 125 beat_fname = f"{prefix_}celerybeat.service" 126 beat_full_path = Path(self.dest, beat_fname) 127 with open(beat_full_path, "w") as o: 128 o.write(f"""[Unit] 129Description=Celery Beat Service{f" ({prefix})" if prefix else ""} 130After=network.target 131 132[Service] 133Type=simple 134WorkingDirectory={self.working_directory} 135ExecStart=/bin/sh -c '{self.celery_bin} \\ 136 -A {app_name} beat \\ 137 --pidfile={self.log_dir}/{prefix_}celerybeat.pid \\ 138 --logfile={self.log_dir}/{prefix_}celerybeat.log \\ 139 --loglevel={log_level}' 140Restart=always 141RestartSec=1 142 143[Install] 144WantedBy=multi-user.target 145""") 146 147 print(f""" 148Service files written to: {self.dest.relative_to(self.working_directory)}. 149Logs written to: {self.log_dir.relative_to(self.working_directory)}. 150 151*Make sure these directories are gitignored!* 152 153Initial deployment (first time only): 154 sudo ln -sf {main_full_path.absolute()} /etc/systemd/system/ 155 sudo ln -sf {beat_full_path.absolute()} /etc/systemd/system/ 156 sudo systemctl enable celery 157 sudo systemctl enable celerybeat 158 sudo systemctl start celery 159 sudo systemctl start celery 160 161Reload services: 162 sudo systemctl daemon-reload 163 sudo systemctl restart celery 164 sudo systemctl restart celerybeat 165""")