Repository: celery/celery

Issue:
Start celery in the detached mode
Dears,

Have been dealing with an issue to start celery in the detached mode. Nothing has been logged.
`root>celery multi start <Node> -A <App> -Q <Queue> -c 1 --without-mingle --without-gossip  --uid=<user> --gid=
<user_group> --pidfile=<path to pid> --logfile=<path to log>`

celery multi start in the verbose mode logs the following command but it fails without any logging as well:
` root>/usr/bin/python3 -m celery -A <App> worker --detach -Q <Queue>-c 1 --uid=<user> --gid=<user_group> --pidfile=<path to pid> --logfile=<path to log> -n <Node> --executable=/usr/bin/python3`

By debugging detach(...) function from the celery.bin.worker.py I identified that detached() has already changed process owner to the  <user>/<user_group>. But os.execv(path, [path] + argv) call passes --uid/--gid prams again. And definitely pointed used does not have permissions so it fails with:
```
return os.initgroups(username, gid) 
OSError: [Errno 1] Operation not permitted
```

```
def detach(path, argv, logfile=None, pidfile=None, uid=None,
           gid=None, umask=None, workdir=None, fake=False, app=None,
           executable=None, hostname=None):
    """Detach program by argv."""
    fake = 1 if C_FAKEFORK else fake
    # `detached()` will attempt to touch the logfile to confirm that error
    # messages won't be lost after detaching stdout/err, but this means we need
    # to pre-format it rather than relying on `setup_logging_subsystem()` like
    # we can elsewhere.
    logfile = node_format(logfile, hostname)
    with detached(logfile, pidfile, uid, gid, umask, workdir, fake, after_forkers=False):                 <<< changes user here
        try:
            if executable is not None:
                path = executable
            os.execv(path, [path] + argv)                                                                 <<< fails here
            return EX_OK
        except Exception:  # pylint: disable=broad-except
            if app is None:
                from celery import current_app
                app = current_app
            app.log.setup_logging_subsystem(
                'ERROR', logfile, hostname=hostname)
            logger.critical("Can't exec %r", ' '.join([path] + argv),
                            exc_info=True)
            return EX_FAILURE
```

The issue reproduced on all 5.x.x versions.

Start celery in the detached mode
Dears,

Have been dealing with an issue to start celery in the detached mode. Nothing has been logged.
`root>celery multi start <Node> -A <App> -Q <Queue> -c 1 --without-mingle --without-gossip  --uid=<user> --gid=
<user_group> --pidfile=<path to pid> --logfile=<path to log>`

celery multi start in the verbose mode logs the following command but it fails without any logging as well:
` root>/usr/bin/python3 -m celery -A <App> worker --detach -Q <Queue>-c 1 --uid=<user> --gid=<user_group> --pidfile=<path to pid> --logfile=<path to log> -n <Node> --executable=/usr/bin/python3`

By debugging detach(...) function from the celery.bin.worker.py I identified that detached() has already changed process owner to the  <user>/<user_group>. But os.execv(path, [path] + argv) call passes --uid/--gid prams again. And definitely pointed used does not have permissions so it fails with:
```
return os.initgroups(username, gid) 
OSError: [Errno 1] Operation not permitted
```

```
def detach(path, argv, logfile=None, pidfile=None, uid=None,
           gid=None, umask=None, workdir=None, fake=False, app=None,
           executable=None, hostname=None):
    """Detach program by argv."""
    fake = 1 if C_FAKEFORK else fake
    # `detached()` will attempt to touch the logfile to confirm that error
    # messages won't be lost after detaching stdout/err, but this means we need
    # to pre-format it rather than relying on `setup_logging_subsystem()` like
    # we can elsewhere.
    logfile = node_format(logfile, hostname)
    with detached(logfile, pidfile, uid, gid, umask, workdir, fake, after_forkers=False):                 <<< changes user here
        try:
            if executable is not None:
                path = executable
            os.execv(path, [path] + argv)                                                                 <<< fails here
            return EX_OK
        except Exception:  # pylint: disable=broad-except
            if app is None:
                from celery import current_app
                app = current_app
            app.log.setup_logging_subsystem(
                'ERROR', logfile, hostname=hostname)
            logger.critical("Can't exec %r", ' '.join([path] + argv),
                            exc_info=True)
            return EX_FAILURE
```

The issue reproduced on all 5.x.x versions.



Discussion:
Hey @ssvasilyev :wave:,
Thank you for opening an issue. We will get back to you as soon as we can.
Also, check out our [Open Collective](https://opencollective.com/celery) and consider backing us - every little helps!

We also offer priority support for our sponsors.
If you require immediate assistance please consider sponsoring us.

This should be easy to fix since we just need to pop them from `argv`.
Care to provide a PR?
Hey @ssvasilyev :wave:,
Thank you for opening an issue. We will get back to you as soon as we can.
Also, check out our [Open Collective](https://opencollective.com/celery) and consider backing us - every little helps!

We also offer priority support for our sponsors.
If you require immediate assistance please consider sponsoring us.

This should be easy to fix since we just need to pop them from `argv`.
Care to provide a PR?

Resolving patch:
diff --git a/celery/bin/worker.py b/celery/bin/worker.py
--- a/celery/bin/worker.py
+++ b/celery/bin/worker.py
@@ -327,6 +327,10 @@ def worker(ctx, hostname=None, pool_cls=None, app=None, uid=None, gid=None,
                 argv.remove('--detach')
             if '-D' in argv:
                 argv.remove('-D')
+            if "--uid" in argv:
+                argv.remove('--uid')
+            if "--gid" in argv:
+                argv.remove('--gid')
 
             return detach(sys.executable,
                           argv,


Test patch: