Repository: ansible/ansible-modules-core

Issue:
sysctl module fails on OpenBSD
OpenBSD's sysctl has no '-p' option:

msg: Failed to reload sysctl: sysctl: unknown option -- p
usage: sysctl [-Aan]
       sysctl [-n] name ...
       sysctl [-nq] name=value ...

Shortly looking at the code shows that there is a case that handles FreeBSD but none for OpenBSD.
https://github.com/ansible/ansible-modules-core/blob/devel/system/sysctl.py#L230



Discussion:
A quick note on this (figured it may be handy): OpenBSD's `sysctl` utility doesn't have a 'reload' option, nor an associated daemon that could be restarted. To set sysctl values in OpenBSD, one simply runs `sysctl some.key.name=value`.  
For example, taken from `man sysctl`:  

```
To set the maximum number of processes allowed in the system to 1000:

           # sysctl kern.maxproc=1000
```

So a solution to this may not be as simple as the conditional for FreeBSD.  
That said, perhaps having `sysctl` parse `/etc/sysctl.conf` (or any other sysctl file put in place by the Ansible) could be a solution, though could be hacky/ugly.  

Just my two-cents on this, I'm not proficient in Python I'm afraid! Maybe I'll hack at it :)

Would something _like_ the following work?   

``` python
        elif get_platform().lower() == 'openbsd':
            # openbsd doesn't support -p, or have a sysctl service, so parse /etc/sysctl.conf
            for line in open(self.sysctl_file):
                li=line.strip()
                if not li.startswith("#"):
                    setting = line.rstrip()
                    rc,out,err = self.module.run_command(self.sysctl_cmd, setting)
```

Emphasis on "like"... because the above code doesn't work, but it gives you an idea of what I was thinking. Perhaps a rather illogical approach, seeing as the desired `sysctl` values are already being presented in dicts elsewhere.  

Like I said: I'm not proficient in Python, so, don't hesitate to point out if the above approach is idiotic!

looks promising, putting on my list for check/implementation

Awesome, thanks @bcoca 

> A quick note on this (figured it may be handy): OpenBSD's `sysctl`
> utility doesn't have a 'reload' option, nor an associated daemon that
> could be restarted. To set sysctl values in OpenBSD, one simply runs
> `sysctl some.key.name=value`.

My opinion is actually that ansible should do that in all OS'es since I
might not want to activate the entire lines in sysctl.conf if I change a
single setting via ansible. Ansible should still write the setting to
sysctl.conf but why reload the entire file?
(if the admin reboots the entire file gets taken into account - as it is
expected)

The reload parameter controls the reload behavior, I do not like the default but it's been grandfathered in. A note should be added that it does not work on OpenBSD.

@nusenu - yes, I agree. Hence why in my other response I state that my approach could be considered illogical, and that it should simply be parameters set by Andible that are presented via the dicts passed from evaluation, not simply parsing the file.

@bcoca - Adding a note rather than trying to have Ansible do the reload? Would the approach of having Ansible execute 'sysctl' on the sysctl key/value pairs passed to it not be an elegant solution?

@cmacrae reload in the other cases implies a 'refresh' of the sysctl.conf file, not just of the parameters passed (which should already be applied).

@bcoca Cool, ok - so would the pseudo code I provided in [my comment above](https://github.com/ansible/ansible-modules-core/issues/1233#issuecomment-100522041) be somewhere in the ballpark for a solution?

kind of, it seems a bit brute force to run through the file

What's the status on this issue? I too would like to be able to apply sysctl.conf changes on OpenBSD without having to restart the system. As it stands I have a task to copy the sysctl.conf file to the remote system, and then four more tasks running sysctl commands to apply each of the four lines in the file without rebooting.

@sysfu waiting for a PR that will fix it, closest thing is @cmacrae code but I've expressed my concerns above


Resolving patch:
diff --git a/system/sysctl.py b/system/sysctl.py
--- a/system/sysctl.py
+++ b/system/sysctl.py
@@ -123,6 +123,8 @@ def __init__(self, module):
 
     def process(self):
 
+        self.platform = get_platform().lower()
+
         # Whitespace is bad
         self.args['name'] = self.args['name'].strip()
         self.args['value'] = self._parse_value(self.args['value'])
@@ -206,7 +208,11 @@ def _parse_value(self, value):
 
     # Use the sysctl command to find the current value 
     def get_token_curr_value(self, token):
-        thiscmd = "%s -e -n %s" % (self.sysctl_cmd, token)
+        if self.platform == 'openbsd':
+            # openbsd doesn't support -e, just drop it
+            thiscmd = "%s -n %s" % (self.sysctl_cmd, token)
+        else:
+            thiscmd = "%s -e -n %s" % (self.sysctl_cmd, token)
         rc,out,err = self.module.run_command(thiscmd)    
         if rc != 0:
             return None
@@ -217,7 +223,11 @@ def get_token_curr_value(self, token):
     def set_token_value(self, token, value):
         if len(value.split()) > 0:
             value = '"' + value + '"'
-        thiscmd = "%s -w %s=%s" % (self.sysctl_cmd, token, value)
+        if self.platform == 'openbsd':
+            # openbsd doesn't accept -w, but since it's not needed, just drop it
+            thiscmd = "%s %s=%s" % (self.sysctl_cmd, token, value)
+        else:
+            thiscmd = "%s -w %s=%s" % (self.sysctl_cmd, token, value)
         rc,out,err = self.module.run_command(thiscmd)
         if rc != 0:
             self.module.fail_json(msg='setting %s failed: %s' % (token, out + err))
@@ -227,9 +237,20 @@ def set_token_value(self, token, value):
     # Run sysctl -p
     def reload_sysctl(self):
         # do it
-        if get_platform().lower() == 'freebsd':
+        if self.platform == 'freebsd':
             # freebsd doesn't support -p, so reload the sysctl service
             rc,out,err = self.module.run_command('/etc/rc.d/sysctl reload')
+        elif self.platform == 'openbsd':
+            # openbsd doesn't support -p and doesn't have a sysctl service,
+            # so we have to set every value with its own sysctl call
+            for k, v in self.file_values.items():
+                rc = 0
+                if k != self.args['name']:
+                    rc = self.set_token_value(k, v)
+                    if rc != 0:
+                        break
+            if rc == 0 and self.args['state'] == "present":
+                rc = self.set_token_value(self.args['name'], self.args['value'])
         else:
             # system supports reloading via the -p flag to sysctl, so we'll use that
             sysctl_args = [self.sysctl_cmd, '-p', self.sysctl_file]


Test patch: