text: #!/usr/bin/python
  # -*- coding: utf-8 -*-
  #
  # Copyright (c) 2016 F5 Networks Inc.
  # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
  
  from __future__ import absolute_import, division, print_function
  __metaclass__ = type
  
  
  ANSIBLE_METADATA = {'metadata_version': '1.1',
                      'status': ['preview'],
                      'supported_by': 'community'}
  
  DOCUMENTATION = r'''
  ---
  module: bigip_sys_db
  short_description: Manage BIG-IP system database variables
  description:
    - Manage BIG-IP system database variables
  version_added: "2.2"
  options:
    key:
      description:
        - The database variable to manipulate.
      required: True
    state:
      description:
        - The state of the variable on the system. When C(present), guarantees
          that an existing variable is set to C(value). When C(reset) sets the
          variable back to the default value. At least one of value and state
          C(reset) are required.
      default: present
      choices:
        - present
        - reset
    value:
      description:
        - The value to set the key to. At least one of value and state C(reset)
          are required.
  notes:
    - Requires BIG-IP version 12.0.0 or greater
  extends_documentation_fragment: f5
  author:
    - Tim Rupp (@caphrim007)
  '''
  
  EXAMPLES = r'''
  - name: Set the boot.quiet DB variable on the BIG-IP
    bigip_sys_db:
      user: admin
      password: secret
      server: lb.mydomain.com
      key: boot.quiet
      value: disable
    delegate_to: localhost
  
  - name: Disable the initial setup screen
    bigip_sys_db:
      user: admin
      password: secret
      server: lb.mydomain.com
      key: setup.run
      value: false
    delegate_to: localhost
  
  - name: Reset the initial setup screen
    bigip_sys_db:
      user: admin
      password: secret
      server: lb.mydomain.com
      key: setup.run
      state: reset
    delegate_to: localhost
  '''
  
  RETURN = r'''
  name:
    description: The key in the system database that was specified
    returned: changed and success
    type: string
    sample: setup.run
  default_value:
    description: The default value of the key
    returned: changed and success
    type: string
    sample: true
  value:
    description: The value that you set the key to
    returned: changed and success
    type: string
    sample: false
  '''
  
  from ansible.module_utils.basic import AnsibleModule
  
  HAS_DEVEL_IMPORTS = False
  
  try:
      # Sideband repository used for dev
      from library.module_utils.network.f5.bigip import HAS_F5SDK
      from library.module_utils.network.f5.bigip import F5Client
      from library.module_utils.network.f5.common import F5ModuleError
      from library.module_utils.network.f5.common import AnsibleF5Parameters
      from library.module_utils.network.f5.common import cleanup_tokens
      from library.module_utils.network.f5.common import fqdn_name
      from library.module_utils.network.f5.common import f5_argument_spec
      try:
          from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
      except ImportError:
          HAS_F5SDK = False
      HAS_DEVEL_IMPORTS = True
  except ImportError:
      # Upstream Ansible
      from ansible.module_utils.network.f5.bigip import HAS_F5SDK
      from ansible.module_utils.network.f5.bigip import F5Client
      from ansible.module_utils.network.f5.common import F5ModuleError
      from ansible.module_utils.network.f5.common import AnsibleF5Parameters
      from ansible.module_utils.network.f5.common import cleanup_tokens
      from ansible.module_utils.network.f5.common import fqdn_name
      from ansible.module_utils.network.f5.common import f5_argument_spec
      try:
          from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
      except ImportError:
          HAS_F5SDK = False
  
  
  class Parameters(AnsibleF5Parameters):
      api_map = {
          'defaultValue': 'default_value'
      }
      api_attributes = ['value']
      updatables = ['value']
      returnables = ['name', 'value', 'default_value']
  
      def to_return(self):
          result = {}
          for returnable in self.returnables:
              result[returnable] = getattr(self, returnable)
          result = self._filter_params(result)
          return result
  
      @property
      def name(self):
          return self._values['key']
  
      @name.setter
      def name(self, value):
          self._values['key'] = value
  
  
  class Changes(Parameters):
      pass
  
  
  class ModuleManager(object):
      def __init__(self, *args, **kwargs):
          self.module = kwargs.get('module', None)
          self.client = kwargs.get('client', None)
          self.have = None
          self.want = Parameters(params=self.module.params)
          self.changes = Changes()
  
      def _update_changed_options(self):
          changed = {}
          for key in Parameters.updatables:
              if getattr(self.want, key) is not None:
                  attr1 = getattr(self.want, key)
                  attr2 = getattr(self.have, key)
                  if attr1 != attr2:
                      changed[key] = attr1
          if self.want.state == 'reset':
              if str(self.have.value) != str(self.have.default_value):
                  changed[self.want.key] = self.have.default_value
          if changed:
              self.changes = Changes(params=changed)
              return True
          return False
  
      def exec_module(self):
          changed = False
          result = dict()
          state = self.want.state
  
          try:
              if state == "present":
                  changed = self.present()
              elif state == "reset":
                  changed = self.reset()
          except iControlUnexpectedHTTPError as e:
              raise F5ModuleError(str(e))
  
          changes = self.changes.to_return()
          result.update(**changes)
          result.update(dict(changed=changed))
          return result
  
      def read_current_from_device(self):
          resource = self.client.api.tm.sys.dbs.db.load(
              name=self.want.key
          )
          result = resource.attrs
          return Parameters(params=result)
  
      def exists(self):
          resource = self.client.api.tm.sys.dbs.db.load(
              name=self.want.key
          )
          if str(resource.value) == str(self.want.value):
              return True
          return False
  
      def present(self):
          if self.exists():
              return False
          else:
              return self.update()
  
      def update(self):
          if self.want.value is None:
              raise F5ModuleError(
                  "When setting a key, a value must be supplied"
              )
          self.have = self.read_current_from_device()
          if not self.should_update():
              return False
          if self.module.check_mode:
              return True
          self.update_on_device()
          return True
  
      def should_update(self):
          result = self._update_changed_options()
          if result:
              return True
          return False
  
      def update_on_device(self):
          params = self.want.api_params()
          resource = self.client.api.tm.sys.dbs.db.load(
              name=self.want.key
          )
          resource.update(**params)
  
      def reset(self):
          self.have = self.read_current_from_device()
          if not self.should_update():
              return False
          if self.module.check_mode:
              return True
          self.reset_on_device()
          self.want.update({'key': self.want.key})
          self.want.update({'value': self.have.default_value})
          if self.exists():
              return True
          else:
              raise F5ModuleError(
                  "Failed to reset the DB variable"
              )
  
      def reset_on_device(self):
          resource = self.client.api.tm.sys.dbs.db.load(
              name=self.want.key
          )
          resource.update(value=self.have.default_value)
  
  
  class ArgumentSpec(object):
      def __init__(self):
          self.supports_check_mode = True
          argument_spec = dict(
              key=dict(required=True),
              state=dict(
                  default='present',
                  choices=['present', 'reset']
              ),
              value=dict()
          )
          self.argument_spec = {}
          self.argument_spec.update(f5_argument_spec)
          self.argument_spec.update(argument_spec)
  
  
  def main():
      spec = ArgumentSpec()
  
      module = AnsibleModule(
          argument_spec=spec.argument_spec,
          supports_check_mode=spec.supports_check_mode
      )
      if not HAS_F5SDK:
          module.fail_json(msg="The python f5-sdk module is required")
  
      try:
          client = F5Client(**module.params)
          mm = ModuleManager(module=module, client=client)
          results = mm.exec_module()
          cleanup_tokens(client)
          module.exit_json(**results)
      except F5ModuleError as ex:
          cleanup_tokens(client)
          module.fail_json(msg=str(ex))
  
  
  if __name__ == '__main__':
      main()
  