Repository: ansible/ansible

Issue:
module/documentation mismatch in systemd module
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
systemd

##### ANSIBLE VERSION
```
ansible 2.4.0
  config file = /home/sxpert/.ansible.cfg
  configured module search path = [u'/home/sxpert/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python2.7/dist-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118]
```

The documentation of the systemd module states that one should be able to do : 
```yml
- name: "restart systemd"
  systemd:
    daemon_reload: "yes"
  become: "yes"
```

yet, when one does this, the following error occurs : 
```
fatal: [testvm]: FAILED! => {
  "changed": false, 
  "failed": true, 
  "msg": "name is also required when specifying state"
}
```
so, which one is it ? 


Discussion:
@sxpert Greetings! Thanks for taking the time to open this issue. In order for the community to handle your issue effectively, we need a bit more information. 

Here are the items we could not find in your description:
- issue type
- ansible version
- component name

Please set the description of this issue with this template:
https://raw.githubusercontent.com/ansible/ansible/devel/.github/ISSUE_TEMPLATE.md

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: issue_missing_data --->
I am able to duplicate this issue, there's no default set for name so it's throwing the error. Even a minor change such as:

`name = dict(aliases=['unit', 'service'], default='service'),`

causes it to work, but then this will act as a default service name I believe which is not correct. I've tried working with:

`    for requires in ('state', 'enabled', 'masked'):
        if requires is not None and unit is None:
            module.fail_json(msg="name is also required when specifying %s" % requires)`

But haven't been able to figure out how to get that working
Bug found, fix PR is comming

Resolving patch:
diff --git a/lib/ansible/modules/system/systemd.py b/lib/ansible/modules/system/systemd.py
--- a/lib/ansible/modules/system/systemd.py
+++ b/lib/ansible/modules/system/systemd.py
@@ -294,7 +294,7 @@ def main():
     }
 
     for requires in ('state', 'enabled', 'masked'):
-        if requires is not None and unit is None:
+        if module.params[requires] is not None and unit is None:
             module.fail_json(msg="name is also required when specifying %s" % requires)
 
     # Run daemon-reload first, if requested
@@ -303,147 +303,148 @@ def main():
         if rc != 0:
             module.fail_json(msg='failure %d during daemon-reload: %s' % (rc, err))
 
-    found = False
-    is_initd = sysv_exists(unit)
-    is_systemd = False
-
-    # check service data, cannot error out on rc as it changes across versions, assume not found
-    (rc, out, err) = module.run_command("%s show '%s'" % (systemctl, unit))
-
-    if request_was_ignored(out) or request_was_ignored(err):
-        # fallback list-unit-files as show does not work on some systems (chroot)
-        # not used as primary as it skips some services (like those using init.d) and requires .service/etc notation
-        (rc, out, err) = module.run_command("%s list-unit-files '%s'" % (systemctl, unit))
-        if rc == 0:
-            is_systemd = True
-
-    elif rc == 0:
-        # load return of systemctl show into dictionary for easy access and return
-        multival = []
-        if out:
-            k = None
-            for line in to_native(out).split('\n'): # systemd can have multiline values delimited with {}
-                if line.strip():
-                    if k is None:
-                        if '=' in line:
-                            k,v = line.split('=', 1)
-                            if v.lstrip().startswith('{'):
-                                if not v.rstrip().endswith('}'):
-                                    multival.append(line)
-                                    continue
-                            result['status'][k] = v.strip()
-                            k = None
-                    else:
-                        if line.rstrip().endswith('}'):
-                            result['status'][k] = '\n'.join(multival).strip()
-                            multival = []
-                            k = None
+    if unit:
+        found = False
+        is_initd = sysv_exists(unit)
+        is_systemd = False
+
+        # check service data, cannot error out on rc as it changes across versions, assume not found
+        (rc, out, err) = module.run_command("%s show '%s'" % (systemctl, unit))
+
+        if request_was_ignored(out) or request_was_ignored(err):
+            # fallback list-unit-files as show does not work on some systems (chroot)
+            # not used as primary as it skips some services (like those using init.d) and requires .service/etc notation
+            (rc, out, err) = module.run_command("%s list-unit-files '%s'" % (systemctl, unit))
+            if rc == 0:
+                is_systemd = True
+
+        elif rc == 0:
+            # load return of systemctl show into dictionary for easy access and return
+            multival = []
+            if out:
+                k = None
+                for line in to_native(out).split('\n'): # systemd can have multiline values delimited with {}
+                    if line.strip():
+                        if k is None:
+                            if '=' in line:
+                                k,v = line.split('=', 1)
+                                if v.lstrip().startswith('{'):
+                                    if not v.rstrip().endswith('}'):
+                                        multival.append(line)
+                                        continue
+                                result['status'][k] = v.strip()
+                                k = None
                         else:
-                            multival.append(line)
-
-            is_systemd = 'LoadState' in result['status'] and result['status']['LoadState'] != 'not-found'
-
-            # Check for loading error
-            if is_systemd and 'LoadError' in result['status']:
-                module.fail_json(msg="Error loading unit file '%s': %s" % (unit, result['status']['LoadError']))
-    else:
-        # Check for systemctl command
-        module.run_command(systemctl, check_rc=True)
-
-    # Does service exist?
-    found = is_systemd or is_initd
-    if is_initd and not is_systemd:
-        module.warn('The service (%s) is actually an init script but the system is managed by systemd' % unit)
-
-    # mask/unmask the service, if requested, can operate on services before they are installed
-    if module.params['masked'] is not None:
-        # state is not masked unless systemd affirms otherwise
-        masked = ('LoadState' in result['status'] and result['status']['LoadState'] == 'masked')
-
-        if masked != module.params['masked']:
-            result['changed'] = True
-            if module.params['masked']:
-                action = 'mask'
-            else:
-                action = 'unmask'
+                            if line.rstrip().endswith('}'):
+                                result['status'][k] = '\n'.join(multival).strip()
+                                multival = []
+                                k = None
+                            else:
+                                multival.append(line)
+
+                is_systemd = 'LoadState' in result['status'] and result['status']['LoadState'] != 'not-found'
+
+                # Check for loading error
+                if is_systemd and 'LoadError' in result['status']:
+                    module.fail_json(msg="Error loading unit file '%s': %s" % (unit, result['status']['LoadError']))
+        else:
+            # Check for systemctl command
+            module.run_command(systemctl, check_rc=True)
 
-            if not module.check_mode:
-                (rc, out, err) = module.run_command("%s %s '%s'" % (systemctl, action, unit))
-                if rc != 0:
-                    # some versions of system CAN mask/unmask non existing services, we only fail on missing if they don't
-                    fail_if_missing(module, found, unit, msg='host')
+        # Does service exist?
+        found = is_systemd or is_initd
+        if is_initd and not is_systemd:
+            module.warn('The service (%s) is actually an init script but the system is managed by systemd' % unit)
 
+        # mask/unmask the service, if requested, can operate on services before they are installed
+        if module.params['masked'] is not None:
+            # state is not masked unless systemd affirms otherwise
+            masked = ('LoadState' in result['status'] and result['status']['LoadState'] == 'masked')
 
-    # Enable/disable service startup at boot if requested
-    if module.params['enabled'] is not None:
+            if masked != module.params['masked']:
+                result['changed'] = True
+                if module.params['masked']:
+                    action = 'mask'
+                else:
+                    action = 'unmask'
 
-        if module.params['enabled']:
-            action = 'enable'
-        else:
-            action = 'disable'
+                if not module.check_mode:
+                    (rc, out, err) = module.run_command("%s %s '%s'" % (systemctl, action, unit))
+                    if rc != 0:
+                        # some versions of system CAN mask/unmask non existing services, we only fail on missing if they don't
+                        fail_if_missing(module, found, unit, msg='host')
 
-        fail_if_missing(module, found, unit, msg='host')
 
-        # do we need to enable the service?
-        enabled = False
-        (rc, out, err) = module.run_command("%s is-enabled '%s'" % (systemctl, unit))
+        # Enable/disable service startup at boot if requested
+        if module.params['enabled'] is not None:
 
-        # check systemctl result or if it is a init script
-        if rc == 0:
-            enabled = True
-        elif rc == 1:
-            # if not a user service and both init script and unit file exist stdout should have enabled/disabled, otherwise use rc entries
-            if not module.params['user'] and \
-               is_initd and \
-               (not out.strip().endswith('disabled') or sysv_is_enabled(unit)):
+            if module.params['enabled']:
+                action = 'enable'
+            else:
+                action = 'disable'
 
+            fail_if_missing(module, found, unit, msg='host')
+
+            # do we need to enable the service?
+            enabled = False
+            (rc, out, err) = module.run_command("%s is-enabled '%s'" % (systemctl, unit))
+
+            # check systemctl result or if it is a init script
+            if rc == 0:
                 enabled = True
+            elif rc == 1:
+                # if not a user service and both init script and unit file exist stdout should have enabled/disabled, otherwise use rc entries
+                if not module.params['user'] and \
+                   is_initd and \
+                   (not out.strip().endswith('disabled') or sysv_is_enabled(unit)):
 
-        # default to current state
-        result['enabled'] = enabled
-
-        # Change enable/disable if needed
-        if enabled != module.params['enabled']:
-            result['changed'] = True
-            if not module.check_mode:
-                (rc, out, err) = module.run_command("%s %s '%s'" % (systemctl, action, unit))
-                if rc != 0:
-                    module.fail_json(msg="Unable to %s service %s: %s" % (action, unit, out + err))
-
-            result['enabled'] = not enabled
-
-    # set service state if requested
-    if module.params['state'] is not None:
-        fail_if_missing(module, found, unit, msg="host")
-
-        # default to desired state
-        result['state'] = module.params['state']
-
-        # What is current service state?
-        if 'ActiveState' in result['status']:
-            action = None
-            if module.params['state'] == 'started':
-                if not is_running_service(result['status']):
-                    action = 'start'
-            elif module.params['state'] == 'stopped':
-                if is_running_service(result['status']):
-                    action = 'stop'
-            else:
-                if not is_running_service(result['status']):
-                    action = 'start'
-                else:
-                    action = module.params['state'][:-2] # remove 'ed' from restarted/reloaded
-                result['state'] = 'started'
+                    enabled = True
+
+            # default to current state
+            result['enabled'] = enabled
 
-            if action:
+            # Change enable/disable if needed
+            if enabled != module.params['enabled']:
                 result['changed'] = True
                 if not module.check_mode:
                     (rc, out, err) = module.run_command("%s %s '%s'" % (systemctl, action, unit))
                     if rc != 0:
-                        module.fail_json(msg="Unable to %s service %s: %s" % (action, unit, err))
-        else:
-            # this should not happen?
-            module.fail_json(msg="Service is in unknown state", status=result['status'])
+                        module.fail_json(msg="Unable to %s service %s: %s" % (action, unit, out + err))
+
+                result['enabled'] = not enabled
+
+        # set service state if requested
+        if module.params['state'] is not None:
+            fail_if_missing(module, found, unit, msg="host")
+
+            # default to desired state
+            result['state'] = module.params['state']
+
+            # What is current service state?
+            if 'ActiveState' in result['status']:
+                action = None
+                if module.params['state'] == 'started':
+                    if not is_running_service(result['status']):
+                        action = 'start'
+                elif module.params['state'] == 'stopped':
+                    if is_running_service(result['status']):
+                        action = 'stop'
+                else:
+                    if not is_running_service(result['status']):
+                        action = 'start'
+                    else:
+                        action = module.params['state'][:-2] # remove 'ed' from restarted/reloaded
+                    result['state'] = 'started'
+
+                if action:
+                    result['changed'] = True
+                    if not module.check_mode:
+                        (rc, out, err) = module.run_command("%s %s '%s'" % (systemctl, action, unit))
+                        if rc != 0:
+                            module.fail_json(msg="Unable to %s service %s: %s" % (action, unit, err))
+            else:
+                # this should not happen?
+                module.fail_json(msg="Service is in unknown state", status=result['status'])
 
 
     module.exit_json(**result)


Test patch: