diff --git a/lib/ansible/modules/network/f5/bigip_device_group_member.py b/lib/ansible/modules/network/f5/bigip_device_group_member.py
new file mode 100644
index 00000000000..b6a1bf912d6
--- /dev/null
+++ b/lib/ansible/modules/network/f5/bigip_device_group_member.py
@@ -0,0 +1,257 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017 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_device_group_member
+short_description: Manages members in a device group
+description:
+  - Manages members in a device group. Members in a device group can only
+    be added or removed, never updated. This is because the members are
+    identified by unique name values and changing that name would invalidate
+    the uniqueness.
+version_added: "2.5"
+options:
+  name:
+    description:
+      - Specifies the name of the device that you want to add to the
+        device group. Often this will be the hostname of the device.
+        This member must be trusted by the device already. Trusting
+        can be done with the C(bigip_device_trust) module and the
+        C(peer_hostname) option to that module.
+    required: True
+  device_group:
+    description:
+      - The device group that you want to add the member to.
+    required: True
+  state:
+    description:
+      - When C(present), ensures that the device group member.
+      - When C(absent), ensures the device group member is removed.
+    default: present
+    choices:
+      - present
+      - absent
+extends_documentation_fragment: f5
+author:
+  - Tim Rupp (@caphrim007)
+'''
+
+EXAMPLES = r'''
+- name: Add the current device to the "device_trust_group" device group
+  bigip_device_group_member:
+    name: "{{ inventory_hostname }}"
+    device_group: device_trust_group
+    password: secret
+    server: lb.mydomain.com
+    state: present
+    user: admin
+  delegate_to: localhost
+
+- name: Add the hosts in the current scope to "device_trust_group"
+  bigip_device_group_member:
+    name: "{{ item }}"
+    device_group: device_trust_group
+    password: secret
+    server: lb.mydomain.com
+    state: present
+    user: admin
+  with_items: "{{ hostvars.keys() }}"
+  run_once: true
+  delegate_to: localhost
+'''
+
+RETURN = r'''
+# only common fields returned
+'''
+
+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 = {}
+
+    api_attributes = []
+
+    returnables = []
+
+    updatables = []
+
+    def to_return(self):
+        result = {}
+        try:
+            for returnable in self.returnables:
+                result[returnable] = getattr(self, returnable)
+            result = self._filter_params(result)
+        except Exception:
+            pass
+        return result
+
+
+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.want = Parameters(params=self.module.params)
+        self.have = None
+        self.changes = Changes()
+
+    def _set_changed_options(self):
+        changed = {}
+        for key in Parameters.returnables:
+            if getattr(self.want, key) is not None:
+                changed[key] = getattr(self.want, key)
+        if changed:
+            self.changes = Changes(params=changed)
+
+    def exec_module(self):
+        changed = False
+        result = dict()
+        state = self.want.state
+
+        try:
+            if state == "present":
+                changed = self.present()
+            elif state == "absent":
+                changed = self.absent()
+        except iControlUnexpectedHTTPError as e:
+            raise F5ModuleError(str(e))
+
+        changes = self.changes.to_return()
+        result.update(**changes)
+        result.update(dict(changed=changed))
+        return result
+
+    def present(self):
+        if self.exists():
+            return False
+        else:
+            return self.create()
+
+    def exists(self):
+        parent = self.client.api.tm.cm.device_groups.device_group.load(
+            name=self.want.device_group
+        )
+        exists = parent.devices_s.devices.exists(name=self.want.name)
+        if exists:
+            return True
+        return False
+
+    def remove(self):
+        if self.module.check_mode:
+            return True
+        self.remove_from_device()
+        if self.exists():
+            raise F5ModuleError("Failed to remove the member from the device group.")
+        return True
+
+    def create(self):
+        self._set_changed_options()
+        if self.module.check_mode:
+            return True
+        self.create_on_device()
+        return True
+
+    def create_on_device(self):
+        parent = self.client.api.tm.cm.device_groups.device_group.load(
+            name=self.want.device_group
+        )
+        parent.devices_s.devices.create(name=self.want.name)
+
+    def absent(self):
+        if self.exists():
+            return self.remove()
+        return False
+
+    def remove_from_device(self):
+        parent = self.client.api.tm.cm.device_groups.device_group.load(
+            name=self.want.device_group
+        )
+        resource = parent.devices_s.devices.load(name=self.want.name)
+        if resource:
+            resource.delete()
+
+
+class ArgumentSpec(object):
+    def __init__(self):
+        self.supports_check_mode = True
+        argument_spec = dict(
+            name=dict(required=True),
+            device_group=dict(required=True),
+            state=dict(
+                default='present',
+                choices=['absent', 'present']
+            )
+        )
+        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()
diff --git a/test/units/modules/network/f5/test_bigip_device_group_member.py b/test/units/modules/network/f5/test_bigip_device_group_member.py
new file mode 100644
index 00000000000..d83c37274bf
--- /dev/null
+++ b/test/units/modules/network/f5/test_bigip_device_group_member.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017 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
+
+import os
+import json
+import pytest
+import sys
+
+from nose.plugins.skip import SkipTest
+if sys.version_info < (2, 7):
+    raise SkipTest("F5 Ansible modules require Python >= 2.7")
+
+from ansible.compat.tests import unittest
+from ansible.compat.tests.mock import Mock
+from ansible.compat.tests.mock import patch
+from ansible.module_utils.basic import AnsibleModule
+
+try:
+    from library.bigip_device_group_member import Parameters
+    from library.bigip_device_group_member import ModuleManager
+    from library.bigip_device_group_member import ArgumentSpec
+    from library.module_utils.network.f5.common import F5ModuleError
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
+    from test.unit.modules.utils import set_module_args
+except ImportError:
+    try:
+        from ansible.modules.network.f5.bigip_device_group_member import Parameters
+        from ansible.modules.network.f5.bigip_device_group_member import ModuleManager
+        from ansible.modules.network.f5.bigip_device_group_member import ArgumentSpec
+        from ansible.module_utils.network.f5.common import F5ModuleError
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
+        from units.modules.utils import set_module_args
+    except ImportError:
+        raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
+
+fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
+fixture_data = {}
+
+
+def load_fixture(name):
+    path = os.path.join(fixture_path, name)
+
+    if path in fixture_data:
+        return fixture_data[path]
+
+    with open(path) as f:
+        data = f.read()
+
+    try:
+        data = json.loads(data)
+    except Exception:
+        pass
+
+    fixture_data[path] = data
+    return data
+
+
+class TestParameters(unittest.TestCase):
+    def test_module_parameters(self):
+        args = dict(
+            name='bigip1',
+            device_group='dg1'
+        )
+
+        p = Parameters(params=args)
+        assert p.name == 'bigip1'
+        assert p.device_group == 'dg1'
+
+
+class TestManager(unittest.TestCase):
+    def setUp(self):
+        self.spec = ArgumentSpec()
+
+    def test_create(self, *args):
+        set_module_args(
+            dict(
+                name="bigip1",
+                device_group="dg1",
+                state="present",
+                server='localhost',
+                user='admin',
+                password='password'
+            )
+        )
+
+        module = AnsibleModule(
+            argument_spec=self.spec.argument_spec,
+            supports_check_mode=self.spec.supports_check_mode
+        )
+        mm = ModuleManager(module=module)
+
+        # Override methods to force specific logic in the module to happen
+        mm.create_on_device = Mock(return_value=True)
+        mm.exists = Mock(return_value=False)
+
+        results = mm.exec_module()
+        assert results['changed'] is True