From 8afa090417bcb6b7007ab6feb1ce3281cdd37001 Mon Sep 17 00:00:00 2001
From: James Cammarata <jimi@sngx.net>
Date: Wed, 7 Dec 2016 21:33:38 -0500
Subject: [PATCH] Resolving differences in core modules post-merge

---
 .../modules/cloud/amazon/cloudformation.py    |   9 -
 lib/ansible/modules/cloud/amazon/ec2.py       |   9 +-
 lib/ansible/modules/cloud/amazon/ec2_ami.py   |  12 +-
 .../modules/cloud/amazon/ec2_ami_find.py      |   2 +-
 lib/ansible/modules/cloud/amazon/ec2_asg.py   |   9 +-
 lib/ansible/modules/cloud/amazon/ec2_eip.py   |   6 -
 lib/ansible/modules/cloud/amazon/ec2_elb.py   |   9 +-
 .../modules/cloud/amazon/ec2_elb_lb.py        |  12 +-
 lib/ansible/modules/cloud/amazon/ec2_facts.py |   2 +-
 lib/ansible/modules/cloud/amazon/ec2_group.py |  10 +-
 lib/ansible/modules/cloud/amazon/ec2_key.py   |  10 +-
 lib/ansible/modules/cloud/amazon/ec2_lc.py    |   7 +-
 .../modules/cloud/amazon/ec2_metric_alarm.py  |   8 +-
 .../cloud/amazon/ec2_scaling_policy.py        |   6 +-
 .../modules/cloud/amazon/ec2_snapshot.py      |   9 +-
 lib/ansible/modules/cloud/amazon/ec2_tag.py   |  10 +-
 lib/ansible/modules/cloud/amazon/ec2_vol.py   |   4 +-
 lib/ansible/modules/cloud/amazon/ec2_vpc.py   |  16 +-
 .../modules/cloud/amazon/ec2_vpc_net.py       |   4 +-
 .../modules/cloud/amazon/elasticache.py       |  12 +-
 .../cloud/amazon/elasticache_subnet_group.py  |  17 +-
 lib/ansible/modules/cloud/amazon/iam.py       |  10 +-
 lib/ansible/modules/cloud/amazon/iam_cert.py  |   4 +-
 .../modules/cloud/amazon/iam_policy.py        |   4 +-
 .../modules/cloud/amazon/rds_param_group.py   |   4 +-
 .../modules/cloud/amazon/rds_subnet_group.py  |  10 +-
 lib/ansible/modules/cloud/amazon/route53.py   |  43 +-
 lib/ansible/modules/cloud/amazon/s3.py        |   4 +-
 lib/ansible/modules/cloud/azure/azure.py      |  16 +-
 .../cloud/azure/azure_rm_publicipaddress.py   |   4 +-
 lib/ansible/modules/cloud/docker/_docker.py   |  31 +-
 .../modules/cloud/google/gc_storage.py        |  13 +-
 lib/ansible/modules/cloud/google/gce.py       |  20 +-
 lib/ansible/modules/cloud/google/gce_net.py   |   2 +-
 .../modules/cloud/openstack/_glance_image.py  |  17 +-
 .../modules/cloud/openstack/_nova_compute.py  |  17 +-
 .../modules/cloud/openstack/_nova_keypair.py  |  14 +-
 .../cloud/openstack/_quantum_floating_ip.py   |  18 +-
 .../_quantum_floating_ip_associate.py         |  17 +-
 .../cloud/openstack/_quantum_network.py       |  14 +-
 .../cloud/openstack/_quantum_router.py        |  13 +-
 .../openstack/_quantum_router_gateway.py      |  11 +-
 .../openstack/_quantum_router_interface.py    |  11 +-
 .../modules/cloud/openstack/os_auth.py        |   6 +-
 .../modules/cloud/openstack/os_floating_ip.py |   1 +
 .../modules/cloud/openstack/os_ironic.py      |  28 +-
 .../modules/cloud/openstack/os_ironic_node.py |   3 +
 .../modules/cloud/openstack/os_object.py      |   4 +-
 .../cloud/openstack/os_security_group.py      |   1 +
 .../cloud/openstack/os_security_group_rule.py |   4 +-
 .../modules/cloud/openstack/os_server.py      |   7 +-
 .../cloud/openstack/os_server_volume.py       |   9 +-
 .../modules/cloud/openstack/os_volume.py      |  10 +-
 .../cloud/rackspace/rax_scaling_group.py      |   4 +-
 .../modules/cloud/vmware/vsphere_guest.py     |   5 +-
 lib/ansible/modules/commands/command.py       |   2 -
 lib/ansible/modules/commands/raw.py           |   1 -
 .../modules/database/mysql/mysql_user.py      |  13 +-
 .../database/postgresql/postgresql_user.py    | 107 ++-
 lib/ansible/modules/files/assemble.py         |   6 +-
 lib/ansible/modules/files/ini_file.py         |   3 +-
 lib/ansible/modules/files/lineinfile.py       |   5 +-
 lib/ansible/modules/files/replace.py          |   5 +-
 lib/ansible/modules/files/template.py         |   8 +-
 lib/ansible/modules/network/basics/get_url.py |   1 +
 lib/ansible/modules/network/basics/uri.py     |   1 +
 .../modules/network/junos/junos_config.py     |   5 +-
 lib/ansible/modules/network/nxos/nxos_acl.py  | 716 +++--------------
 .../network/nxos/nxos_acl_interface.py        | 389 ++-------
 lib/ansible/modules/network/nxos/nxos_bgp.py  | 757 +++---------------
 .../modules/network/nxos/nxos_bgp_af.py       | 657 ++-------------
 .../modules/network/nxos/nxos_bgp_neighbor.py | 650 ++-------------
 .../network/nxos/nxos_bgp_neighbor_af.py      | 659 ++-------------
 .../modules/network/nxos/nxos_evpn_global.py  | 368 ++-------
 .../modules/network/nxos/nxos_evpn_vni.py     | 655 ++-------------
 .../modules/network/nxos/nxos_feature.py      | 648 ++-------------
 .../modules/network/nxos/nxos_file_copy.py    | 659 ++-------------
 lib/ansible/modules/network/nxos/nxos_hsrp.py | 645 ++-------------
 lib/ansible/modules/network/nxos/nxos_igmp.py | 659 ++-------------
 .../network/nxos/nxos_igmp_interface.py       | 680 ++--------------
 .../network/nxos/nxos_interface_ospf.py       | 645 ++-------------
 .../modules/network/nxos/nxos_ip_interface.py | 665 ++-------------
 .../modules/network/nxos/nxos_ntp_options.py  |   1 +
 lib/ansible/modules/network/nxos/nxos_ospf.py | 374 ++-------
 .../modules/network/nxos/nxos_ospf_vrf.py     | 637 ++-------------
 .../network/nxos/nxos_overlay_global.py       | 694 +++-------------
 lib/ansible/modules/network/nxos/nxos_pim.py  | 651 ++-------------
 .../network/nxos/nxos_pim_rp_address.py       | 653 ++-------------
 lib/ansible/modules/network/nxos/nxos_ping.py | 670 ++--------------
 .../modules/network/nxos/nxos_reboot.py       | 660 ++-------------
 .../modules/network/nxos/nxos_rollback.py     | 680 +++-------------
 lib/ansible/modules/network/nxos/nxos_smu.py  | 644 ++-------------
 .../modules/network/nxos/nxos_snmp_host.py    |  35 +-
 .../network/nxos/nxos_snmp_location.py        |   2 +
 .../modules/network/nxos/nxos_static_route.py | 647 ++-------------
 .../modules/network/nxos/nxos_switchport.py   |   4 +-
 lib/ansible/modules/network/nxos/nxos_vlan.py | 670 ++--------------
 lib/ansible/modules/network/nxos/nxos_vpc.py  | 637 ++-------------
 .../network/nxos/nxos_vpc_interface.py        | 646 ++-------------
 lib/ansible/modules/network/nxos/nxos_vrf.py  | 640 ++-------------
 .../modules/network/nxos/nxos_vrf_af.py       | 660 ++-------------
 .../network/nxos/nxos_vrf_interface.py        | 663 ++-------------
 lib/ansible/modules/network/nxos/nxos_vrrp.py |  28 +-
 .../modules/network/nxos/nxos_vtp_password.py |   4 +-
 .../modules/network/nxos/nxos_vxlan_vtep.py   |  13 +-
 .../network/nxos/nxos_vxlan_vtep_vni.py       |   8 +-
 .../modules/packaging/os/rhn_register.py      |   4 +-
 lib/ansible/modules/packaging/os/rpm_key.py   |   2 +-
 lib/ansible/modules/packaging/os/yum.py       |   2 +-
 lib/ansible/modules/system/cron.py            |   6 +-
 lib/ansible/modules/system/setup.py           |   2 +-
 lib/ansible/modules/system/user.py            |   1 +
 lib/ansible/modules/windows/win_lineinfile.py |  43 +-
 lib/ansible/modules/windows/win_msi.ps1       |  10 +-
 lib/ansible/modules/windows/win_msi.py        |   2 +-
 115 files changed, 2651 insertions(+), 17913 deletions(-)

diff --git a/lib/ansible/modules/cloud/amazon/cloudformation.py b/lib/ansible/modules/cloud/amazon/cloudformation.py
index a2cbf2c99c..c05ae2df28 100644
--- a/lib/ansible/modules/cloud/amazon/cloudformation.py
+++ b/lib/ansible/modules/cloud/amazon/cloudformation.py
@@ -39,35 +39,28 @@ options:
     description:
       - name of the cloudformation stack
     required: true
-    default: null
-    aliases: []
   disable_rollback:
     description:
       - If a stacks fails to form, rollback will remove the stack
     required: false
     default: "false"
     choices: [ "true", "false" ]
-    aliases: []
   template_parameters:
     description:
       - a list of hashes of all the template variables for the stack
     required: false
     default: {}
-    aliases: []
   state:
     description:
       - If state is "present", stack will be created.  If state is "present" and if stack exists and template has changed, it will be updated.
         If state is "absent", stack will be removed.
     required: true
-    default: null
-    aliases: []
   template:
     description:
       - The local path of the cloudformation template. This parameter is mutually exclusive with 'template_url'. Either one of them is required if "state" parameter is "present"
         Must give full path to the file, relative to the working directory. If using roles this may look like "roles/cloudformation/files/cloudformation-example.json"
     required: false
     default: null
-    aliases: []
   notification_arns:
     description:
       - The Simple Notification Service (SNS) topic ARNs to publish stack related events.
@@ -79,14 +72,12 @@ options:
       - the path of the cloudformation stack policy. A policy cannot be removed once placed, but it can be modified. (for instance, [allow all updates](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html#d0e9051)
     required: false
     default: null
-    aliases: []
     version_added: "1.9"
   tags:
     description:
       - Dictionary of tags to associate with stack and its resources during stack creation. Can be updated later, updating tags removes previous entries.
     required: false
     default: null
-    aliases: []
     version_added: "1.4"
   template_url:
     description:
diff --git a/lib/ansible/modules/cloud/amazon/ec2.py b/lib/ansible/modules/cloud/amazon/ec2.py
index 84f2687617..d19f06f369 100755
--- a/lib/ansible/modules/cloud/amazon/ec2.py
+++ b/lib/ansible/modules/cloud/amazon/ec2.py
@@ -56,7 +56,7 @@ options:
   region:
     version_added: "1.2"
     description:
-      - The AWS region to use.  Must be specified if ec2_url is not used. If not specified then the value of the EC2_REGION environment variable, if any, is used.
+      - The AWS region to use.  Must be specified if ec2_url is not used. If not specified then the value of the EC2_REGION environment variable, if any, is used. See U(http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region)
     required: false
     default: null
     aliases: [ 'aws_region', 'ec2_region' ]
@@ -69,16 +69,17 @@ options:
     aliases: [ 'aws_zone', 'ec2_zone' ]
   instance_type:
     description:
-      - instance type to use for the instance
+      - instance type to use for the instance, see U(http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html)
     required: true
     default: null
     aliases: []
   tenancy:
     version_added: "1.9"
     description:
-      - An instance with a tenancy of "dedicated" runs on single-tenant hardware and can only be launched into a VPC. Valid values are "default" or "dedicated". Note that to use dedicated tenancy you MUST specify a vpc_subnet_id as well. Dedicated tenancy is not available for EC2 "micro" instances.
+      - An instance with a tenancy of "dedicated" runs on single-tenant hardware and can only be launched into a VPC. Note that to use dedicated tenancy you MUST specify a vpc_subnet_id as well. Dedicated tenancy is not available for EC2 "micro" instances.
     required: false
     default: default
+    choices: [ "default", "dedicated" ]
     aliases: []
   spot_price:
     version_added: "1.5"
@@ -143,6 +144,7 @@ options:
       - enable detailed monitoring (CloudWatch) for instance
     required: false
     default: null
+    choices: [ "yes", "no" ]
     aliases: []
   user_data:
     version_added: "0.9"
@@ -178,6 +180,7 @@ options:
       - when provisioning within vpc, assign a public IP address. Boto library must be 2.13.0+
     required: false
     default: null
+    choices: [ "yes", "no" ]
     aliases: []
   private_ip:
     version_added: "1.2"
diff --git a/lib/ansible/modules/cloud/amazon/ec2_ami.py b/lib/ansible/modules/cloud/amazon/ec2_ami.py
index 075fe15734..de3a31c4a7 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_ami.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_ami.py
@@ -51,12 +51,6 @@ options:
       - create or deregister/delete image
     required: false
     default: 'present'
-  region:
-    description:
-      - The AWS region to use.  Must be specified if ec2_url is not used. If not specified then the value of the EC2_REGION environment variable, if any, is used.
-    required: false
-    default: null
-    aliases: [ 'aws_region', 'ec2_region' ]
   description:
     description:
       - An optional human-readable string describing the contents and purpose of the AMI.
@@ -74,10 +68,10 @@ options:
     required: false
     default: null
   device_mapping:
-    version_added: "1.9"
+    version_added: "2.0"
     description:
       - An optional list of device hashes/dictionaries with custom configurations (same block-device-mapping parameters)
-      - Valid properties include: device_name, volume_type, size (in GB), delete_on_termination (boolean), no_device (boolean), snapshot_id, iops (for io1 volume_type)
+      - "Valid properties include: device_name, volume_type, size (in GB), delete_on_termination (boolean), no_device (boolean), snapshot_id, iops (for io1 volume_type)"
     required: false
     default: null
   delete_snapshot:
@@ -305,6 +299,7 @@ import time
 try:
     import boto
     import boto.ec2
+    from boto.ec2.blockdevicemapping import BlockDeviceType, BlockDeviceMapping
     HAS_BOTO = True
 except ImportError:
     HAS_BOTO = False
@@ -365,6 +360,7 @@ def create_image(module, ec2):
     wait_timeout = int(module.params.get('wait_timeout'))
     description = module.params.get('description')
     no_reboot = module.params.get('no_reboot')
+    device_mapping = module.params.get('device_mapping')
     tags =  module.params.get('tags')
     launch_permissions = module.params.get('launch_permissions')
 
diff --git a/lib/ansible/modules/cloud/amazon/ec2_ami_find.py b/lib/ansible/modules/cloud/amazon/ec2_ami_find.py
index c7947c9638..c6b986bdd8 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_ami_find.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_ami_find.py
@@ -22,7 +22,7 @@ ANSIBLE_METADATA = {'status': ['preview'],
 DOCUMENTATION = '''
 ---
 module: ec2_ami_find
-version_added: 2.0
+version_added: '2.0'
 short_description: Searches for AMIs to obtain the AMI ID and other information
 description:
   - Returns list of matching AMIs with AMI ID, along with other useful information
diff --git a/lib/ansible/modules/cloud/amazon/ec2_asg.py b/lib/ansible/modules/cloud/amazon/ec2_asg.py
index f7ced3b957..e295d0008b 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_asg.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_asg.py
@@ -69,7 +69,7 @@ options:
     required: false
   replace_all_instances:
     description:
-      - In a rolling fashion, replace all instances with an old launch configuration with one from the current launch configuraiton.
+      - In a rolling fashion, replace all instances with an old launch configuration with one from the current launch configuration.
     required: false
     version_added: "1.8"
     default: False
@@ -91,11 +91,6 @@ options:
     required: false
     version_added: "1.8"
     default: True
-  region:
-    description:
-      - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
-    required: false
-    aliases: ['aws_region', 'ec2_region']
   vpc_zone_identifier:
     description:
       - List of VPC subnets to use
@@ -142,7 +137,7 @@ options:
         - An ordered list of criteria used for selecting instances to be removed from the Auto Scaling group when reducing capacity.
         - For 'Default', when used to create a new autoscaling group, the "Default"i value is used. When used to change an existent autoscaling group, the current termination policies are maintained.
     required: false
-    default: Default. Eg, when used to create a new autoscaling group, the “Default” value is used. When used to change an existent autoscaling group, the current termination policies are mantained
+    default: Default
     choices: ['OldestInstance', 'NewestInstance', 'OldestLaunchConfiguration', 'ClosestToNextInstanceHour', 'Default']
     version_added: "2.0"
   notification_topic:
diff --git a/lib/ansible/modules/cloud/amazon/ec2_eip.py b/lib/ansible/modules/cloud/amazon/ec2_eip.py
index 6e6fa5dbfd..22d950f9fb 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_eip.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_eip.py
@@ -47,12 +47,6 @@ options:
     required: false
     choices: ['present', 'absent']
     default: present
-  region:
-    description:
-      - the EC2 region to use
-    required: false
-    default: null
-    aliases: [ ec2_region ]
   in_vpc:
     description:
       - allocate an EIP inside a VPC or not
diff --git a/lib/ansible/modules/cloud/amazon/ec2_elb.py b/lib/ansible/modules/cloud/amazon/ec2_elb.py
index fee8ff22bb..cd2cf5fbae 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_elb.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_elb.py
@@ -45,11 +45,6 @@ options:
       - List of ELB names, required for registration. The ec2_elbs fact should be used if there was a previous de-register.
     required: false
     default: None
-  region:
-    description:
-      - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
-    required: false
-    aliases: ['aws_region', 'ec2_region']
   enable_availability_zone:
     description:
       - Whether to enable the availability zone of the instance on the target ELB if the availability zone has not already
@@ -77,7 +72,9 @@ options:
     required: false
     default: 0
     version_added: "1.6"
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 """
 
 EXAMPLES = """
diff --git a/lib/ansible/modules/cloud/amazon/ec2_elb_lb.py b/lib/ansible/modules/cloud/amazon/ec2_elb_lb.py
index 8bd02a698e..ca87a1cb3a 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_elb_lb.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_elb_lb.py
@@ -82,7 +82,7 @@ options:
     version_added: "2.0"
   health_check:
     description:
-      - An associative array of health check configuration settigs (see example)
+      - An associative array of health check configuration settings (see example)
     require: false
     default: None
   access_logs:
@@ -131,7 +131,7 @@ options:
     version_added: "2.0"
   cross_az_load_balancing:
     description:
-      - Distribute load across all configured Availablity Zones
+      - Distribute load across all configured Availability Zones
     required: false
     default: "no"
     choices: ["yes", "no"]
@@ -163,7 +163,9 @@ options:
     required: false
     version_added: "2.1"
 
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 """
 
 EXAMPLES = """
@@ -271,7 +273,7 @@ EXAMPLES = """
     purge_listeners: no
 
 # Normally, this module will leave availability zones that are enabled
-# on the ELB alone. If purge_zones is true, then any extreneous zones
+# on the ELB alone. If purge_zones is true, then any extraneous zones
 # will be removed
 - local_action:
     module: ec2_elb_lb
@@ -762,7 +764,7 @@ class ElbManager(object):
                 # Does it match exactly?
                 if listener_as_tuple != existing_listener_found:
                     # The ports are the same but something else is different,
-                    # so we'll remove the exsiting one and add the new one
+                    # so we'll remove the existing one and add the new one
                     listeners_to_remove.append(existing_listener_found)
                     listeners_to_add.append(listener_as_tuple)
                 else:
diff --git a/lib/ansible/modules/cloud/amazon/ec2_facts.py b/lib/ansible/modules/cloud/amazon/ec2_facts.py
index 463cef8cae..498cf9c2df 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_facts.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_facts.py
@@ -33,7 +33,7 @@ options:
         required: false
         default: 'yes'
         choices: ['yes', 'no']
-        version_added: 1.5.1
+        version_added: '1.5.1'
 description:
      - This module fetches data from the metadata servers in ec2 (aws) as per
        http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html.
diff --git a/lib/ansible/modules/cloud/amazon/ec2_group.py b/lib/ansible/modules/cloud/amazon/ec2_group.py
index 5a85bcab25..b381218f49 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_group.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_group.py
@@ -49,12 +49,6 @@ options:
       - List of firewall outbound rules to enforce in this group (see example). If none are supplied, a default all-out rule is assumed. If an empty list is supplied, no outbound rules will be enabled.
     required: false
     version_added: "1.6"
-  region:
-    description:
-      - the EC2 region to use
-    required: false
-    default: null
-    aliases: []
   state:
     version_added: "1.4"
     description:
@@ -78,7 +72,9 @@ options:
     default: 'true'
     aliases: []
 
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 
 notes:
   - If a rule declares a group_name and that group doesn't exist, it will be
diff --git a/lib/ansible/modules/cloud/amazon/ec2_key.py b/lib/ansible/modules/cloud/amazon/ec2_key.py
index 3ebf563f15..69d96fed97 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_key.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_key.py
@@ -35,12 +35,6 @@ options:
     description:
       - Public key material.
     required: false
-  region:
-    description:
-      - the EC2 region to use
-    required: false
-    default: null
-    aliases: []
   state:
     description:
       - create or delete keypair
@@ -62,7 +56,9 @@ options:
     aliases: []
     version_added: "1.6"
 
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+ - aws
+ - ec2
 author: "Vincent Viallet (@zbal)"
 '''
 
diff --git a/lib/ansible/modules/cloud/amazon/ec2_lc.py b/lib/ansible/modules/cloud/amazon/ec2_lc.py
index 54bb209974..7a8754b899 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_lc.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_lc.py
@@ -59,11 +59,6 @@ options:
     description:
       - A list of security groups to apply to the instances. For VPC instances, specify security group IDs. For EC2-Classic, specify either security group names or IDs.
     required: false
-  region:
-    description:
-      - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
-    required: false
-    aliases: ['aws_region', 'ec2_region']
   volumes:
     description:
       - a list of volume dicts, each containing device name and optionally ephemeral id or snapshot id. Size and type (and number of iops for io device type) must be specified for a new volume or a root volume, and may be passed for a snapshot volume. For any volume, a volume size less than 1 will be interpreted as a request not to create the volume.
@@ -110,7 +105,7 @@ options:
       - Id of ClassicLink enabled VPC
     required: false
     version_added: "2.0"
-  classic_link_vpc_security_groups"
+  classic_link_vpc_security_groups:
     description:
       - A list of security group id's with which to associate the ClassicLink VPC instances.
     required: false
diff --git a/lib/ansible/modules/cloud/amazon/ec2_metric_alarm.py b/lib/ansible/modules/cloud/amazon/ec2_metric_alarm.py
index 017f238571..984211bc27 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_metric_alarm.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_metric_alarm.py
@@ -33,7 +33,7 @@ options:
         required: true
         choices: ['present', 'absent']
     name:
-        desciption:
+        description:
           - Unique name for the alarm
         required: true
     metric:
@@ -75,7 +75,7 @@ options:
         options: ['Seconds','Microseconds','Milliseconds','Bytes','Kilobytes','Megabytes','Gigabytes','Terabytes','Bits','Kilobits','Megabits','Gigabits','Terabits','Percent','Count','Bytes/Second','Kilobytes/Second','Megabytes/Second','Gigabytes/Second','Terabytes/Second','Bits/Second','Kilobits/Second','Megabits/Second','Gigabits/Second','Terabits/Second','Count/Second','None']
     description:
         description:
-          - A longer desciption of the alarm
+          - A longer description of the alarm
         required: false
     dimensions:
         description:
@@ -93,7 +93,9 @@ options:
         description:
           - A list of the names of action(s) to take when the alarm is in the 'ok' status
         required: false
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 """
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/ec2_scaling_policy.py b/lib/ansible/modules/cloud/amazon/ec2_scaling_policy.py
index 16287387b5..bea3bfbca8 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_scaling_policy.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_scaling_policy.py
@@ -41,7 +41,7 @@ options:
       - Name of the associated autoscaling group
     required: true
   adjustment_type:
-    desciption:
+    description:
       - The type of change in capacity of the autoscaling group
     required: false
     choices: ['ChangeInCapacity','ExactCapacity','PercentChangeInCapacity']
@@ -57,7 +57,9 @@ options:
     description:
       - The minimum period of time between which autoscaling actions can take place
     required: false
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 """
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/ec2_snapshot.py b/lib/ansible/modules/cloud/amazon/ec2_snapshot.py
index b8911fbb7e..b962e18760 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_snapshot.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_snapshot.py
@@ -26,11 +26,6 @@ description:
     - creates an EC2 snapshot from an existing EBS volume
 version_added: "1.5"
 options:
-  region:
-    description:
-      - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
-    required: false
-    aliases: ['aws_region', 'ec2_region']
   volume_id:
     description:
       - volume from which to take the snapshot
@@ -86,7 +81,9 @@ options:
     version_added: "2.0"
 
 author: "Will Thames (@willthames)"
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/ec2_tag.py b/lib/ansible/modules/cloud/amazon/ec2_tag.py
index d05f988e2a..0fe20e1786 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_tag.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_tag.py
@@ -26,12 +26,6 @@ description:
     - Creates, removes and lists tags from any EC2 resource.  The resource is referenced by its resource id (e.g. an instance being i-XXXXXXX). It is designed to be used with complex args (tags), see the examples.  This module has a dependency on python-boto.
 version_added: "1.3"
 options:
-  region:
-    description:
-      - region in which the resource exists. 
-    required: false
-    default: null
-    aliases: ['aws_region', 'ec2_region']
   resource:
     description:
       - The EC2 resource id. 
@@ -53,7 +47,9 @@ options:
     aliases: []
 
 author: "Lester Wade (@lwade)"
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/ec2_vol.py b/lib/ansible/modules/cloud/amazon/ec2_vol.py
index 9e7d5d02ea..cd76703f43 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_vol.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_vol.py
@@ -105,7 +105,9 @@ options:
     choices: ['absent', 'present', 'list']
     version_added: "1.6"
 author: "Lester Wade (@lwade)"
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/ec2_vpc.py b/lib/ansible/modules/cloud/amazon/ec2_vpc.py
index 669aa56fa6..5b0cfc51b0 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_vpc.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_vpc.py
@@ -91,7 +91,9 @@ options:
     required: true
     choices: [ "present", "absent" ]
 author: "Carson Gee (@carsongee)"
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
@@ -476,6 +478,7 @@ def create_vpc(module, vpc_conn):
 
     # Handle Internet gateway (create/delete igw)
     igw = None
+    igw_id = None
     igws = vpc_conn.get_all_internet_gateways(filters={'attachment.vpc-id': vpc.id})
     if len(igws) > 1:
         module.fail_json(msg='EC2 returned more than one Internet Gateway for id %s, aborting' % vpc.id)
@@ -499,6 +502,9 @@ def create_vpc(module, vpc_conn):
             except EC2ResponseError as e:
                 module.fail_json(msg='Unable to delete Internet Gateway, error: {0}'.format(e))
 
+    if igw is not None:
+        igw_id = igw.id
+
     # Handle route tables - this may be worth splitting into a
     # different module but should work fine here. The strategy to stay
     # idempotent is to basically build all the route tables as
@@ -602,6 +608,7 @@ def create_vpc(module, vpc_conn):
                     module.fail_json(msg='Unable to delete old route table {0}, error: {1}'.format(rt.id, e))
 
     vpc_dict = get_vpc_info(vpc)
+
     created_vpc_id = vpc.id
     returned_subnets = []
     current_subnets = vpc_conn.get_all_subnets(filters={ 'vpc_id': vpc.id })
@@ -624,7 +631,7 @@ def create_vpc(module, vpc_conn):
         subnets_in_play = len(subnets)
         returned_subnets.sort(key=lambda x: order.get(x['cidr'], subnets_in_play))
 
-    return (vpc_dict, created_vpc_id, returned_subnets, changed)
+    return (vpc_dict, created_vpc_id, returned_subnets, igw_id, changed)
 
 def terminate_vpc(module, vpc_conn, vpc_id=None, cidr=None):
     """
@@ -723,6 +730,7 @@ def main():
     else:
         module.fail_json(msg="region must be specified")
 
+    igw_id = None
     if module.params.get('state') == 'absent':
         vpc_id = module.params.get('vpc_id')
         cidr = module.params.get('cidr_block')
@@ -730,9 +738,9 @@ def main():
         subnets_changed = None
     elif module.params.get('state') == 'present':
         # Changed is always set to true when provisioning a new VPC
-        (vpc_dict, new_vpc_id, subnets_changed, changed) = create_vpc(module, vpc_conn)
+        (vpc_dict, new_vpc_id, subnets_changed, igw_id, changed) = create_vpc(module, vpc_conn)
 
-    module.exit_json(changed=changed, vpc_id=new_vpc_id, vpc=vpc_dict, subnets=subnets_changed)
+    module.exit_json(changed=changed, vpc_id=new_vpc_id, vpc=vpc_dict, igw_id=igw_id, subnets=subnets_changed)
 
 # import module snippets
 from ansible.module_utils.basic import *
diff --git a/lib/ansible/modules/cloud/amazon/ec2_vpc_net.py b/lib/ansible/modules/cloud/amazon/ec2_vpc_net.py
index fe3e99adf4..7b7e0e4647 100644
--- a/lib/ansible/modules/cloud/amazon/ec2_vpc_net.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_vpc_net.py
@@ -76,7 +76,9 @@ options:
     default: false
     required: false
 
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/elasticache.py b/lib/ansible/modules/cloud/amazon/elasticache.py
index 80372643d0..00098b171e 100644
--- a/lib/ansible/modules/cloud/amazon/elasticache.py
+++ b/lib/ansible/modules/cloud/amazon/elasticache.py
@@ -74,7 +74,7 @@ options:
       - The subnet group name to associate with. Only use if inside a vpc. Required if inside a vpc
     required: false
     default: None
-    version_added: "1.7"
+    version_added: "2.0"
   security_group_ids:
     description:
       - A list of vpc security group names to associate with this cache cluster. Only use if inside a vpc
@@ -103,13 +103,9 @@ options:
     required: false
     default: no
     choices: [ "yes", "no" ]
-  region:
-    description:
-      - The AWS region to use. If not specified then the value of the AWS_REGION or EC2_REGION environment variable, if any, is used.
-    required: true
-    default: null
-    aliases: ['aws_region', 'ec2_region']
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 """
 
 EXAMPLES = """
diff --git a/lib/ansible/modules/cloud/amazon/elasticache_subnet_group.py b/lib/ansible/modules/cloud/amazon/elasticache_subnet_group.py
index b2927cf33e..1e5708c03e 100644
--- a/lib/ansible/modules/cloud/amazon/elasticache_subnet_group.py
+++ b/lib/ansible/modules/cloud/amazon/elasticache_subnet_group.py
@@ -31,34 +31,25 @@ options:
       - Specifies whether the subnet should be present or absent.
     required: true
     default: present
-    aliases: []
     choices: [ 'present' , 'absent' ]
   name:
     description:
       - Database subnet group identifier.
     required: true
-    default: null
-    aliases: []
   description:
     description:
       - Elasticache subnet group description. Only set when a new group is added.
     required: false
     default: null
-    aliases: []
   subnets:
     description:
       - List of subnet IDs that make up the Elasticache subnet group.
     required: false
     default: null
-    aliases: []
-  region:
-    description:
-      - The AWS region to use. If not specified then the value of the AWS_REGION or EC2_REGION environment variable, if any, is used.
-    required: true
-    default: null
-    aliases: ['aws_region', 'ec2_region']
-author: Tim Mahoney
-extends_documentation_fragment: aws
+author: "Tim Mahoney (@timmahoney)"
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/iam.py b/lib/ansible/modules/cloud/amazon/iam.py
index 4fb56dd160..70b9da0f5e 100644
--- a/lib/ansible/modules/cloud/amazon/iam.py
+++ b/lib/ansible/modules/cloud/amazon/iam.py
@@ -36,24 +36,22 @@ options:
     description:
       - Name of IAM resource to create or identify
     required: true
-    aliases: []
   new_name:
     description:
       - When state is update, will replace name with new_name on IAM resource
     required: false
-    aliases: []
+    default: null
   new_path:
     description:
       - When state is update, will replace the path with new_path on the IAM resource
     required: false
-    aliases: []
+    default: null
   state:
     description:
       - Whether to create, delete or update the IAM resource. Note, roles cannot be updated.
     required: true
     default: null
     choices: [ "present", "absent", "update" ]
-    aliases: []
   path:
     description:
       - When creating or updating, specify the desired path of the resource. If state is present, it will replace the current path to match what is passed in when they do not match.
@@ -77,13 +75,11 @@ options:
     required: false
     default: null
     choices: [ "create", "remove", "active", "inactive"]
-    aliases: []
   key_count:
     description:
       - When access_key_state is create it will ensure this quantity of keys are present. Defaults to 1.
     required: false
     default: '1'
-    aliases: []
   access_key_ids:
     description:
       - A list of the keys that you want impacted by the access_key_state parameter.
@@ -92,13 +88,11 @@ options:
       - A list of groups the user should belong to. When update, will gracefully remove groups not listed.
     required: false
     default: null
-    aliases: []
   password:
     description:
       - When type is user and state is present, define the users login password. Also works with update. Note that always returns changed.
     required: false
     default: null
-    aliases: []
   update_password:
     required: false
     default: always
diff --git a/lib/ansible/modules/cloud/amazon/iam_cert.py b/lib/ansible/modules/cloud/amazon/iam_cert.py
index 5f88798efd..6e71b5552f 100644
--- a/lib/ansible/modules/cloud/amazon/iam_cert.py
+++ b/lib/ansible/modules/cloud/amazon/iam_cert.py
@@ -89,7 +89,9 @@ options:
 
 requirements: [ "boto" ]
 author: Jonathan I. Davila
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/iam_policy.py b/lib/ansible/modules/cloud/amazon/iam_policy.py
index 1f601860b6..97be3f4051 100644
--- a/lib/ansible/modules/cloud/amazon/iam_policy.py
+++ b/lib/ansible/modules/cloud/amazon/iam_policy.py
@@ -62,7 +62,9 @@ options:
 notes:
   - 'Currently boto does not support the removal of Managed Policies, the module will not work removing/adding managed policies.'
 author: "Jonathan I. Davila (@defionscode)"
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/rds_param_group.py b/lib/ansible/modules/cloud/amazon/rds_param_group.py
index 6a0518a06e..154fed391a 100644
--- a/lib/ansible/modules/cloud/amazon/rds_param_group.py
+++ b/lib/ansible/modules/cloud/amazon/rds_param_group.py
@@ -65,7 +65,9 @@ options:
     default: null
     aliases: []
 author: "Scott Anderson (@tastychutney)"
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/rds_subnet_group.py b/lib/ansible/modules/cloud/amazon/rds_subnet_group.py
index 5c08a9bb39..bec08cf61d 100644
--- a/lib/ansible/modules/cloud/amazon/rds_subnet_group.py
+++ b/lib/ansible/modules/cloud/amazon/rds_subnet_group.py
@@ -51,14 +51,10 @@ options:
     required: false
     default: null
     aliases: []
-  region:
-    description:
-      - The AWS region to use. If not specified then the value of the AWS_REGION or EC2_REGION environment variable, if any, is used.
-    required: true
-    default: null
-    aliases: ['aws_region', 'ec2_region']
 author: "Scott Anderson (@tastychutney)"
-extends_documentation_fragment: aws
+extends_documentation_fragment:
+    - aws
+    - ec2
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/amazon/route53.py b/lib/ansible/modules/cloud/amazon/route53.py
index cf16c1a4fe..dfcd325fd8 100644
--- a/lib/ansible/modules/cloud/amazon/route53.py
+++ b/lib/ansible/modules/cloud/amazon/route53.py
@@ -30,33 +30,26 @@ options:
     description:
       - Specifies the action to take.  
     required: true
-    default: null
-    aliases: []
     choices: [ 'get', 'create', 'delete' ]
   zone:
     description:
       - The DNS zone to modify
     required: true
-    default: null
-    aliases: []
   hosted_zone_id:
     description:
       - The Hosted Zone ID of the DNS zone to modify
     required: false
-    version_added: 2.0
+    version_added: "2.0"
     default: null
   record:
     description:
       - The full DNS record to create or delete
     required: true
-    default: null
-    aliases: []
   ttl:
     description:
       - The TTL to give the new record
     required: false
     default: 3600 (one hour)
-    aliases: []
   type:
     description:
       - The type of DNS record to create
@@ -66,40 +59,36 @@ options:
     description:
       - Indicates if this is an alias record.
     required: false
-    version_added: 1.9
+    version_added: "1.9"
     default: False
-    aliases: []
     choices: [ 'True', 'False' ]
   alias_hosted_zone_id:
     description:
       - The hosted zone identifier.
     required: false
-    version_added: 1.9
+    version_added: "1.9"
     default: null
   alias_evaluate_target_health:
     description:
       - Whether or not to evaluate an alias target health. Useful for aliases to Elastic Load Balancers.
     required: false
-    version_added: "2.0"
+    version_added: "2.1"
     default: false
   value:
     description:
       - The new value when creating a DNS record.  Multiple comma-spaced values are allowed for non-alias records.  When deleting a record all values for the record must be specified or Route53 will not delete it.
     required: false
     default: null
-    aliases: []
   overwrite:
     description:
       - Whether an existing record should be overwritten on create if values do not match
     required: false
     default: null
-    aliases: []
   retry_interval:
     description:
       - In the case that route53 is still servicing a prior request, this module will wait and try again after this many seconds. If you have many domain names, the default of 500 seconds may be too long.
     required: false
     default: 500
-    aliases: []
   private_zone:
     description:
       - If set to true, the private zone matching the requested name within the domain will be used if there are both public and private zones. The default is to use the public zone.
@@ -316,6 +305,7 @@ import distutils.version
 
 try:
     import boto
+    import boto.ec2
     from boto import route53
     from boto.route53 import Route53Connection
     from boto.route53.record import Record, ResourceRecordSets
@@ -496,26 +486,11 @@ def main():
     except boto.exception.BotoServerError as e:
         module.fail_json(msg = e.error_message)
 
-    # Get all the existing hosted zones and save their ID's
-    zones = {}
-    results = conn.get_all_hosted_zones()
-    for r53zone in results['ListHostedZonesResponse']['HostedZones']:
-        # only save this zone id if the private status of the zone matches
-        # the private_zone_in boolean specified in the params
-        if module.boolean(r53zone['Config'].get('PrivateZone', False)) == private_zone_in:
-            zone_id = r53zone['Id'].replace('/hostedzone/', '')
-            # only save when unique hosted_zone_id is given and is equal
-            # hosted_zone_id_in is specified in the params
-            if hosted_zone_id_in and zone_id == hosted_zone_id_in:
-                zones[r53zone['Name']] = zone_id
-            elif not hosted_zone_id_in:
-                zones[r53zone['Name']] = zone_id
+    # Find the named zone ID
+    zone = get_zone_by_name(conn, module, zone_in, private_zone_in, hosted_zone_id_in, vpc_id_in)
 
     # Verify that the requested zone is already defined in Route53
-    if not zone_in in zones and hosted_zone_id_in:
-        errmsg = "Hosted_zone_id %s does not exist in Route53" % hosted_zone_id_in
-        module.fail_json(msg = errmsg)
-    if not zone_in in zones:
+    if zone is None:
         errmsg = "Zone %s does not exist in Route53" % zone_in
         module.fail_json(msg = errmsg)
 
@@ -551,6 +526,8 @@ def main():
             record['ttl'] = rset.ttl
             record['value'] = ','.join(sorted(rset.resource_records))
             record['values'] = sorted(rset.resource_records)
+            if hosted_zone_id_in:
+                record['hosted_zone_id'] = hosted_zone_id_in
             record['identifier'] = rset.identifier
             record['weight'] = rset.weight
             record['region'] = rset.region
diff --git a/lib/ansible/modules/cloud/amazon/s3.py b/lib/ansible/modules/cloud/amazon/s3.py
index 045f40dd01..9974a4f467 100755
--- a/lib/ansible/modules/cloud/amazon/s3.py
+++ b/lib/ansible/modules/cloud/amazon/s3.py
@@ -584,7 +584,7 @@ def main():
                 if overwrite == 'always':
                     download_s3file(module, s3, bucket, obj, dest, retries, version=version)
                 else:
-                    module.exit_json(msg="Local and remote object are identical, ignoring. Use overwrite parameter to force.", changed=False)
+                    module.exit_json(msg="Local and remote object are identical, ignoring. Use overwrite=always parameter to force.", changed=False)
             else:
                 sum_matches = False
 
@@ -594,7 +594,7 @@ def main():
                     module.exit_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force download.")
 
         # Firstly, if key_matches is TRUE and overwrite is not enabled, we EXIT with a helpful message.
-        if sum_matches is True and overwrite is False:
+        if sum_matches is True and overwrite == 'never':
             module.exit_json(msg="Local and remote object are identical, ignoring. Use overwrite parameter to force.", changed=False)
 
     # if our mode is a PUT operation (upload), go through the procedure as appropriate ...
diff --git a/lib/ansible/modules/cloud/azure/azure.py b/lib/ansible/modules/cloud/azure/azure.py
index 6892e54b7a..60cdbbe047 100644
--- a/lib/ansible/modules/cloud/azure/azure.py
+++ b/lib/ansible/modules/cloud/azure/azure.py
@@ -38,12 +38,12 @@ options:
     default: null
   subscription_id:
     description:
-      - azure subscription id. Overrides the AZURE_SUBSCRIPTION_ID environement variable.
+      - azure subscription id. Overrides the AZURE_SUBSCRIPTION_ID environment variable.
     required: false
     default: null
   management_cert_path:
     description:
-      - path to an azure management certificate associated with the subscription id. Overrides the AZURE_CERT_PATH environement variable.
+      - path to an azure management certificate associated with the subscription id. Overrides the AZURE_CERT_PATH environment variable.
     required: false
     default: null
   storage_account:
@@ -114,13 +114,6 @@ options:
     required: false
     default: 'present'
     aliases: []
-  reset_pass_atlogon:
-    description:
-      - Reset the admin password on first logon for windows hosts
-    required: false
-    default: "no"
-    version_added: "2.0"
-    choices: [ "yes", "no" ]
   auto_updates:
     description:
       - Enable Auto Updates on Windows Machines
@@ -258,7 +251,7 @@ AZURE_ROLE_SIZES = ['ExtraSmall',
                     'Standard_DS14',
                     'Standard_G1',
                     'Standard_G2',
-                    'Sandard_G3',
+                    'Standard_G3',
                     'Standard_G4',
                     'Standard_G5']
 
@@ -516,7 +509,7 @@ def terminate_virtual_machine(module, azure):
 
 
 def get_azure_creds(module):
-    # Check modul args for credentials, then check environment vars
+    # Check module args for credentials, then check environment vars
     subscription_id = module.params.get('subscription_id')
     if not subscription_id:
         subscription_id = os.environ.get('AZURE_SUBSCRIPTION_ID', None)
@@ -553,7 +546,6 @@ def main():
             wait=dict(type='bool', default=False),
             wait_timeout=dict(default=600),
             wait_timeout_redirects=dict(default=300),
-            reset_pass_atlogon=dict(type='bool', default=False),
             auto_updates=dict(type='bool', default=False),
             enable_winrm=dict(type='bool', default=True),
         )
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress.py b/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress.py
index 70ee6c5e88..7aa05d4ed5 100644
--- a/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress.py
+++ b/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress.py
@@ -264,17 +264,17 @@ class AzureRMPublicIPAddress(AzureRMModuleBase):
     def create_or_update_pip(self, pip):
         try:
             poller = self.network_client.public_ip_addresses.create_or_update(self.resource_group, self.name, pip)
+            pip = self.get_poller_result(poller)
         except Exception as exc:
             self.fail("Error creating or updating {0} - {1}".format(self.name, str(exc)))
-        pip = self.get_poller_result(poller)
         return pip_to_dict(pip)
 
     def delete_pip(self):
         try:
             poller = self.network_client.public_ip_addresses.delete(self.resource_group, self.name)
+            self.get_poller_result(poller)
         except Exception as exc:
             self.fail("Error deleting {0} - {1}".format(self.name, str(exc)))
-        self.get_poller_result(poller)
         # Delete returns nada. If we get here, assume that all is well.
         self.results['state']['status'] = 'Deleted'
         return True
diff --git a/lib/ansible/modules/cloud/docker/_docker.py b/lib/ansible/modules/cloud/docker/_docker.py
index f1bfff1d73..08adf3b907 100644
--- a/lib/ansible/modules/cloud/docker/_docker.py
+++ b/lib/ansible/modules/cloud/docker/_docker.py
@@ -74,11 +74,10 @@ options:
     version_added: "1.5"
   ports:
     description:
-      - List containing private to public port mapping specification. Use docker
-      - 'CLI-style syntax: C(8000), C(9000:8000), or C(0.0.0.0:9000:8000)'
-      - where  8000 is a container port, 9000 is a host port, and 0.0.0.0 is
-      - a host interface. The container ports need to be exposed either in the 
-      - Dockerfile or via the next option.
+      - "List containing private to public port mapping specification.
+        Use docker 'CLI-style syntax: C(8000), C(9000:8000), or C(0.0.0.0:9000:8000)'
+        where 8000 is a container port, 9000 is a host port, and 0.0.0.0 is - a host interface.
+        The container ports need to be exposed either in the Dockerfile or via the C(expose) option."
     default: null
     version_added: "1.5"
   expose:
@@ -154,10 +153,7 @@ options:
     description:
       - RAM allocated to the container as a number of bytes or as a human-readable
         string like "512MB". Leave as "0" to specify no limit.
-    required: false
-    default: null
-    aliases: []
-    default: 256MB
+    default: 0
   docker_url:
     description:
       - URL of the host running the docker daemon. This will default to the env
@@ -878,7 +874,7 @@ class DockerManager(object):
         we lack the capability.
         """
         if not self._capabilities:
-            self._check_capabilties()
+            self._check_capabilities()
 
         if capability in self._capabilities:
             return True
@@ -1054,7 +1050,7 @@ class DockerManager(object):
             elif p_len == 3:
                 # Bind `container_port` of the container to port `parts[1]` on
                 # IP `parts[0]` of the host machine. If `parts[1]` empty bind
-                # to a dynamically allocacted port of IP `parts[0]`.
+                # to a dynamically allocated port of IP `parts[0]`.
                 bind = (parts[0], int(parts[1])) if parts[1] else (parts[0],)
 
             if container_port in binds:
@@ -1643,23 +1639,10 @@ class DockerManager(object):
                   'name':         self.module.params.get('name'),
                   'stdin_open':   self.module.params.get('stdin_open'),
                   'tty':          self.module.params.get('tty'),
-                  'volumes_from': self.module.params.get('volumes_from'),
-                  'dns':          self.module.params.get('dns'),
                   'cpuset':       self.module.params.get('cpu_set'),
                   'cpu_shares':   self.module.params.get('cpu_shares'),
                   'user':         self.module.params.get('docker_user'),
                   }
-        if docker.utils.compare_version('1.10', self.client.version()['ApiVersion']) >= 0:
-            params['volumes_from'] = ""
-
-        if params['volumes_from'] is not None:
-            self.ensure_capability('volumes_from')
-
-        extra_params = {}
-        if self.module.params.get('insecure_registry'):
-            if self.ensure_capability('insecure_registry', fail=False):
-                extra_params['insecure_registry'] = self.module.params.get('insecure_registry')
-
         if self.ensure_capability('host_config', fail=False):
             params['host_config'] = self.create_host_config()
 
diff --git a/lib/ansible/modules/cloud/google/gc_storage.py b/lib/ansible/modules/cloud/google/gc_storage.py
index 4d4004c0f8..001de7c700 100644
--- a/lib/ansible/modules/cloud/google/gc_storage.py
+++ b/lib/ansible/modules/cloud/google/gc_storage.py
@@ -31,25 +31,20 @@ options:
     description:
       - Bucket name. 
     required: true
-    default: null 
-    aliases: []
   object:
     description:
       - Keyname of the object inside the bucket. Can be also be used to create "virtual directories" (see examples).
     required: false
     default: null
-    aliases: []
   src:
     description:
       - The source file path when performing a PUT operation.
     required: false
     default: null
-    aliases: []
   dest:
     description:
       - The destination file path when downloading an object/key with a GET operation.
     required: false
-    aliases: []
   force:
     description:
       - Forces an overwrite either locally on the filesystem or remotely with the object/key. Used with PUT and GET operations.
@@ -62,23 +57,21 @@ options:
     required: false
     default: private 
   headers:
-    version_added: 2.0
+    version_added: "2.0"
     description:
       - Headers to attach to object.
     required: false
-    default: {}
+    default: '{}'
   expiration:
     description:
-      - Time limit (in seconds) for the URL generated and returned by GCA when performing a mode=put or mode=get_url operation. This url is only avaialbe when public-read is the acl for the object.
+      - Time limit (in seconds) for the URL generated and returned by GCA when performing a mode=put or mode=get_url operation. This url is only available when public-read is the acl for the object.
     required: false
     default: null
-    aliases: []
   mode:
     description:
       - Switches the module behaviour between upload, download, get_url (return download url) , get_str (download object as string), create (bucket) and delete (bucket). 
     required: true
     default: null
-    aliases: []
     choices: [ 'get', 'put', 'get_url', 'get_str', 'delete', 'create' ]
   gs_secret_key:
     description:
diff --git a/lib/ansible/modules/cloud/google/gce.py b/lib/ansible/modules/cloud/google/gce.py
index a6dba47ecb..802a7a1393 100644
--- a/lib/ansible/modules/cloud/google/gce.py
+++ b/lib/ansible/modules/cloud/google/gce.py
@@ -36,35 +36,30 @@ options:
        - image string to use for the instance
     required: false
     default: "debian-7"
-    aliases: []
   instance_names:
     description:
       - a comma-separated list of instance names to create or destroy
     required: false
     default: null
-    aliases: []
   machine_type:
     description:
       - machine type to use for the instance, use 'n1-standard-1' by default
     required: false
     default: "n1-standard-1"
-    aliases: []
   metadata:
     description:
       - a hash/dictionary of custom data for the instance;
         '{"key":"value", ...}'
     required: false
     default: null
-    aliases: []
   service_account_email:
-    version_added: 1.5.1
+    version_added: "1.5.1"
     description:
       - service account email
     required: false
     default: null
-    aliases: []
   service_account_permissions:
-    version_added: 2.0
+    version_added: "2.0"
     description:
       - service account permissions (see
         U(https://cloud.google.com/sdk/gcloud/reference/compute/instances/create),
@@ -78,7 +73,7 @@ options:
       "storage-rw", "taskqueue", "userinfo-email"
     ]
   pem_file:
-    version_added: 1.5.1
+    version_added: "1.5.1"
     description:
       - path to the pem file associated with the service account email
         This option is deprecated. Use 'credentials_file'.
@@ -91,12 +86,11 @@ options:
     default: null
     required: false
   project_id:
-    version_added: 1.5.1
+    version_added: "1.5.1"
     description:
       - your GCE project ID
     required: false
     default: null
-    aliases: []
   name:
     description:
       - either a name of a single instance or when used with 'num_instances',
@@ -126,7 +120,6 @@ options:
       - if set, create the instance with a persistent boot disk
     required: false
     default: "false"
-    aliases: []
   disks:
     description:
       - a list of persistent disks to attach to the instance; a string value
@@ -135,7 +128,6 @@ options:
         will be the boot disk (which must be READ_WRITE).
     required: false
     default: null
-    aliases: []
     version_added: "1.7"
   state:
     description:
@@ -148,13 +140,11 @@ options:
       - a comma-separated list of tags to associate with the instance
     required: false
     default: null
-    aliases: []
   zone:
     description:
       - the GCE zone to use
     required: true
     default: "us-central1-a"
-    aliases: []
   ip_forward:
     version_added: "1.9"
     description:
@@ -162,14 +152,12 @@ options:
         gateways)
     required: false
     default: "false"
-    aliases: []
   external_ip:
     version_added: "1.9"
     description:
       - type of external ip, ephemeral by default; alternatively, a list of fixed gce ips or ip names can be given (if there is not enough specified ip, 'ephemeral' will be used). Specify 'none' if no external ip is desired.
     required: false
     default: "ephemeral"
-    aliases: []
   disk_auto_delete:
     version_added: "1.9"
     description:
diff --git a/lib/ansible/modules/cloud/google/gce_net.py b/lib/ansible/modules/cloud/google/gce_net.py
index b33a81113c..aec0a29427 100644
--- a/lib/ansible/modules/cloud/google/gce_net.py
+++ b/lib/ansible/modules/cloud/google/gce_net.py
@@ -26,7 +26,7 @@ module: gce_net
 version_added: "1.5"
 short_description: create/destroy GCE networks and firewall rules
 description:
-    - This module can create and destroy Google Compue Engine networks and
+    - This module can create and destroy Google Compute Engine networks and
       firewall rules U(https://developers.google.com/compute/docs/networking).
       The I(name) parameter is reserved for referencing a network while the
       I(fwname) parameter is used to reference firewall rules.
diff --git a/lib/ansible/modules/cloud/openstack/_glance_image.py b/lib/ansible/modules/cloud/openstack/_glance_image.py
index a589e7d0bc..a97255241a 100644
--- a/lib/ansible/modules/cloud/openstack/_glance_image.py
+++ b/lib/ansible/modules/cloud/openstack/_glance_image.py
@@ -116,7 +116,10 @@ options:
      required: false
      default: publicURL
      version_added: "1.7"
-requirements: ["glanceclient", "keystoneclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-glanceclient"
+    - "python-keystoneclient"
 
 '''
 
@@ -136,9 +139,14 @@ EXAMPLES = '''
 import time
 try:
     import glanceclient
-    from keystoneclient.v2_0 import client as ksclient
+    HAS_GLANCECLIENT = True
 except ImportError:
-    print("failed=True msg='glanceclient and keystone client are required'")
+    HAS_GLANCECLIENT = False
+try:
+    from keystoneclient.v2_0 import client as ksclient
+    HAS_KEYSTONECLIENT = True
+except ImportError:
+    HAS_KEYSTONECLIENT= False
 
 
 def _get_ksclient(module, kwargs):
@@ -269,4 +277,5 @@ def main():
 # this is magic, see lib/ansible/module_common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
diff --git a/lib/ansible/modules/cloud/openstack/_nova_compute.py b/lib/ansible/modules/cloud/openstack/_nova_compute.py
index e14ca3407d..0bea21048f 100644
--- a/lib/ansible/modules/cloud/openstack/_nova_compute.py
+++ b/lib/ansible/modules/cloud/openstack/_nova_compute.py
@@ -19,15 +19,16 @@
 
 import operator
 import os
+import time
 
 try:
     from novaclient.v1_1 import client as nova_client
     from novaclient.v1_1 import floating_ips
     from novaclient import exceptions
     from novaclient import utils
-    import time
+    HAS_NOVACLIENT = True
 except ImportError:
-    print("failed=True msg='novaclient is required for this module'")
+    HAS_NOVACLIENT = False
 
 ANSIBLE_METADATA = {'status': ['deprecated'],
                     'supported_by': 'community',
@@ -37,7 +38,7 @@ DOCUMENTATION = '''
 ---
 module: nova_compute
 version_added: "1.2"
-deprecated: Deprecated in 1.10. Use os_server instead
+deprecated: Deprecated in 2.0. Use os_server instead
 short_description: Create/Delete VMs from OpenStack
 description:
    - Create or Remove virtual machines from Openstack.
@@ -179,7 +180,9 @@ options:
      required: false
      default: None
      version_added: "1.9"
-requirements: ["novaclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-novaclient"
 '''
 
 EXAMPLES = '''
@@ -567,6 +570,9 @@ def main():
         ],
     )
 
+    if not HAS_NOVACLIENT:
+        module.fail_json(msg='python-novaclient is required for this module')
+
     nova = nova_client.Client(module.params['login_username'],
                               module.params['login_password'],
                               module.params['login_tenant_name'],
@@ -593,4 +599,5 @@ def main():
 # this is magic, see lib/ansible/module_common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
diff --git a/lib/ansible/modules/cloud/openstack/_nova_keypair.py b/lib/ansible/modules/cloud/openstack/_nova_keypair.py
index 045235b099..914db91bf2 100644
--- a/lib/ansible/modules/cloud/openstack/_nova_keypair.py
+++ b/lib/ansible/modules/cloud/openstack/_nova_keypair.py
@@ -17,12 +17,13 @@
 # You should have received a copy of the GNU General Public License
 # along with this software.  If not, see <http://www.gnu.org/licenses/>.
 
+import time
 try:
     from novaclient.v1_1 import client as nova_client
     from novaclient import exceptions as exc
-    import time
+    HAS_NOVACLIENT = True
 except ImportError:
-    print("failed=True msg='novaclient is required for this module to work'")
+    HAS_NOVACLIENT = False
 
 ANSIBLE_METADATA = {'status': ['deprecated'],
                     'supported_by': 'community',
@@ -81,7 +82,9 @@ options:
      required: false
      default: None
 
-requirements: ["novaclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-novaclient"
 '''
 EXAMPLES = '''
 - name: Create a key pair with the running users public key
@@ -110,6 +113,8 @@ def main():
         state                           = dict(default='present', choices=['absent', 'present'])
     ))
     module = AnsibleModule(argument_spec=argument_spec)
+    if not HAS_NOVACLIENT:
+        module.fail_json(msg='python-novaclient is required for this module to work')
 
     nova = nova_client.Client(module.params['login_username'],
                               module.params['login_password'],
@@ -151,5 +156,6 @@ def main():
 # this is magic, see lib/ansible/module.params['common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
 
diff --git a/lib/ansible/modules/cloud/openstack/_quantum_floating_ip.py b/lib/ansible/modules/cloud/openstack/_quantum_floating_ip.py
index 362e56487e..9c72c431d0 100644
--- a/lib/ansible/modules/cloud/openstack/_quantum_floating_ip.py
+++ b/lib/ansible/modules/cloud/openstack/_quantum_floating_ip.py
@@ -16,6 +16,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this software.  If not, see <http://www.gnu.org/licenses/>.
 
+import time
+
 try:
     from novaclient.v1_1 import client as nova_client
     try:
@@ -23,9 +25,9 @@ try:
     except ImportError:
         from quantumclient.quantum import client
     from keystoneclient.v2_0 import client as ksclient
-    import time
+    HAVE_DEPS = True
 except ImportError:
-    print("failed=True msg='novaclient,keystoneclient and quantumclient (or neutronclient) are required'")
+    HAVE_DEPS = False
 
 ANSIBLE_METADATA = {'status': ['deprecated'],
                     'supported_by': 'community',
@@ -89,7 +91,11 @@ options:
      required: false
      default: None
      version_added: "1.5"
-requirements: ["novaclient", "quantumclient", "neutronclient", "keystoneclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-novaclient"
+    - "python-neutronclient or python-quantumclient"
+    - "python-keystoneclient"
 '''
 
 EXAMPLES = '''
@@ -252,6 +258,9 @@ def main():
     ))
     module = AnsibleModule(argument_spec=argument_spec)
 
+    if not HAVE_DEPS:
+        module.fail_json(msg='python-novaclient, python-keystoneclient, and either python-neutronclient or python-quantumclient are required')
+
     try:
         nova = nova_client.Client(module.params['login_username'], module.params['login_password'],
             module.params['login_tenant_name'], module.params['auth_url'], region_name=module.params['region_name'], service_type='compute')
@@ -285,5 +294,6 @@ def main():
 # this is magic, see lib/ansible/module.params['common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
 
diff --git a/lib/ansible/modules/cloud/openstack/_quantum_floating_ip_associate.py b/lib/ansible/modules/cloud/openstack/_quantum_floating_ip_associate.py
index ef86e4b594..f7eed5fe86 100644
--- a/lib/ansible/modules/cloud/openstack/_quantum_floating_ip_associate.py
+++ b/lib/ansible/modules/cloud/openstack/_quantum_floating_ip_associate.py
@@ -16,6 +16,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this software.  If not, see <http://www.gnu.org/licenses/>.
 
+import time
 try:
     from novaclient.v1_1 import client as nova_client
     try:
@@ -23,9 +24,9 @@ try:
     except ImportError:
         from quantumclient.quantum import client
     from keystoneclient.v2_0 import client as ksclient
-    import time
+    HAVE_DEPS = True
 except ImportError:
-    print "failed=True msg='novaclient, keystone, and quantumclient (or neutronclient) client are required'"
+    HAVE_DEPS = False
 
 ANSIBLE_METADATA = {'status': ['deprecated'],
                     'supported_by': 'community',
@@ -81,7 +82,11 @@ options:
         - floating ip that should be assigned to the instance
      required: true
      default: None
-requirements: ["quantumclient", "neutronclient", "keystoneclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-novaclient"
+    - "python-neutronclient or python-quantumclient"
+    - "python-keystoneclient"
 '''
 
 EXAMPLES = '''
@@ -192,6 +197,9 @@ def main():
     ))
     module = AnsibleModule(argument_spec=argument_spec)
 
+    if not HAVE_DEPS:
+        module.fail_json(msg='python-novaclient, python-keystoneclient, and either python-neutronclient or python-quantumclient are required')
+
     try:
         nova = nova_client.Client(module.params['login_username'], module.params['login_password'],
                                  module.params['login_tenant_name'], module.params['auth_url'], service_type='compute')
@@ -220,5 +228,6 @@ def main():
 # this is magic, see lib/ansible/module.params['common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
 
diff --git a/lib/ansible/modules/cloud/openstack/_quantum_network.py b/lib/ansible/modules/cloud/openstack/_quantum_network.py
index d31fcd961d..db82e90d33 100644
--- a/lib/ansible/modules/cloud/openstack/_quantum_network.py
+++ b/lib/ansible/modules/cloud/openstack/_quantum_network.py
@@ -22,8 +22,9 @@ try:
     except ImportError:
         from quantumclient.quantum import client
     from keystoneclient.v2_0 import client as ksclient
+    HAVE_DEPS = True
 except ImportError:
-    print("failed=True msg='quantumclient (or neutronclient) and keystone client are required'")
+    HAVE_DEPS = False
 
 ANSIBLE_METADATA = {'status': ['deprecated'],
                     'supported_by': 'community',
@@ -108,7 +109,10 @@ options:
         - Whether the state should be marked as up or down
      required: false
      default: true
-requirements: ["quantumclient", "neutronclient", "keystoneclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-neutronclient or python-quantumclient"
+    - "python-keystoneclient"
 
 '''
 
@@ -259,6 +263,9 @@ def main():
     ))
     module = AnsibleModule(argument_spec=argument_spec)
 
+    if not HAVE_DEPS:
+        module.fail_json(msg='python-keystoneclient and either python-neutronclient or python-quantumclient are required')
+
     if module.params['provider_network_type'] in ['vlan' , 'flat']:
             if not module.params['provider_physical_network']:
                 module.fail_json(msg = " for vlan and flat networks, variable provider_physical_network should be set.")
@@ -290,5 +297,6 @@ def main():
 # this is magic, see lib/ansible/module.params['common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
 
diff --git a/lib/ansible/modules/cloud/openstack/_quantum_router.py b/lib/ansible/modules/cloud/openstack/_quantum_router.py
index 37b812a5e5..c65f916d6b 100644
--- a/lib/ansible/modules/cloud/openstack/_quantum_router.py
+++ b/lib/ansible/modules/cloud/openstack/_quantum_router.py
@@ -22,8 +22,9 @@ try:
     except ImportError:
         from quantumclient.quantum import client
     from keystoneclient.v2_0 import client as ksclient
+    HAVE_DEPS = True
 except ImportError:
-    print("failed=True msg='quantumclient (or neutronclient) and keystone client are required'")
+    HAVE_DEPS = False
 
 ANSIBLE_METADATA = {'status': ['deprecated'],
                     'supported_by': 'community',
@@ -84,7 +85,10 @@ options:
         - desired admin state of the created router .
      required: false
      default: true
-requirements: ["quantumclient", "neutronclient", "keystoneclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-neutronclient or python-quantumclient"
+    - "python-keystoneclient"
 '''
 
 EXAMPLES = '''
@@ -189,6 +193,8 @@ def main():
         admin_state_up                  = dict(type='bool', default=True),
     ))
     module = AnsibleModule(argument_spec=argument_spec)
+    if not HAVE_DEPS:
+        module.fail_json(msg='python-keystoneclient and either python-neutronclient or python-quantumclient are required')
 
     neutron = _get_neutron_client(module, module.params)
     _set_tenant_id(module)
@@ -212,5 +218,6 @@ def main():
 # this is magic, see lib/ansible/module.params['common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
 
diff --git a/lib/ansible/modules/cloud/openstack/_quantum_router_gateway.py b/lib/ansible/modules/cloud/openstack/_quantum_router_gateway.py
index c67b90f62c..af6179bc62 100644
--- a/lib/ansible/modules/cloud/openstack/_quantum_router_gateway.py
+++ b/lib/ansible/modules/cloud/openstack/_quantum_router_gateway.py
@@ -22,6 +22,7 @@ try:
     except ImportError:
         from quantumclient.quantum import client
     from keystoneclient.v2_0 import client as ksclient
+    HAVE_DEPS = True
 except ImportError:
     HAVE_DEPS = False
 
@@ -79,7 +80,10 @@ options:
         - Name of the external network which should be attached to the router.
      required: true
      default: None
-requirements: ["quantumclient", "neutronclient", "keystoneclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-neutronclient or python-quantumclient"
+    - "python-keystoneclient"
 '''
 
 EXAMPLES = '''
@@ -192,6 +196,8 @@ def main():
             state              = dict(default='present', choices=['absent', 'present']),
     ))
     module = AnsibleModule(argument_spec=argument_spec)
+    if not HAVE_DEPS:
+        module.fail_json(msg='python-keystoneclient and either python-neutronclient or python-quantumclient are required')
 
     neutron = _get_neutron_client(module, module.params)
     router_id = _get_router_id(module, neutron)
@@ -220,5 +226,6 @@ def main():
 # this is magic, see lib/ansible/module.params['common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
 
diff --git a/lib/ansible/modules/cloud/openstack/_quantum_router_interface.py b/lib/ansible/modules/cloud/openstack/_quantum_router_interface.py
index 6405ac6182..b2a1784d99 100644
--- a/lib/ansible/modules/cloud/openstack/_quantum_router_interface.py
+++ b/lib/ansible/modules/cloud/openstack/_quantum_router_interface.py
@@ -22,6 +22,7 @@ try:
     except ImportError:
         from quantumclient.quantum import client
     from keystoneclient.v2_0 import client as ksclient
+    HAVE_DEPS = True
 except ImportError:
     HAVE_DEPS = False
 
@@ -84,7 +85,10 @@ options:
         - Name of the tenant whose subnet has to be attached.
      required: false
      default: None
-requirements: ["quantumclient", "keystoneclient"]
+requirements:
+    - "python >= 2.6"
+    - "python-neutronclient or python-quantumclient"
+    - "python-keystoneclient"
 '''
 
 EXAMPLES = '''
@@ -224,6 +228,8 @@ def main():
             state                           = dict(default='present', choices=['absent', 'present']),
     ))
     module = AnsibleModule(argument_spec=argument_spec)
+    if not HAVE_DEPS:
+        module.fail_json(msg='python-keystoneclient and either python-neutronclient or python-quantumclient are required')
 
     neutron = _get_neutron_client(module, module.params)
     _set_tenant_id(module)
@@ -253,5 +259,6 @@ def main():
 # this is magic, see lib/ansible/module.params['common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
 
diff --git a/lib/ansible/modules/cloud/openstack/os_auth.py b/lib/ansible/modules/cloud/openstack/os_auth.py
index a780ae1c5c..c46945a3d6 100644
--- a/lib/ansible/modules/cloud/openstack/os_auth.py
+++ b/lib/ansible/modules/cloud/openstack/os_auth.py
@@ -34,6 +34,9 @@ version_added: "2.0"
 author: "Monty Taylor (@emonty)"
 description:
    - Retrieve an auth token from an OpenStack Cloud
+requirements:
+    - "python >= 2.6"
+    - "shade"
 extends_documentation_fragment: openstack
 '''
 
@@ -69,4 +72,5 @@ def main():
 # this is magic, see lib/ansible/module_common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
diff --git a/lib/ansible/modules/cloud/openstack/os_floating_ip.py b/lib/ansible/modules/cloud/openstack/os_floating_ip.py
index 04db985f06..16c217c2d8 100644
--- a/lib/ansible/modules/cloud/openstack/os_floating_ip.py
+++ b/lib/ansible/modules/cloud/openstack/os_floating_ip.py
@@ -97,6 +97,7 @@ options:
           IP completely, or only detach it from the server. Default is to detach only.
      required: false
      default: false
+     version_added: "2.1"
 requirements: ["shade"]
 '''
 
diff --git a/lib/ansible/modules/cloud/openstack/os_ironic.py b/lib/ansible/modules/cloud/openstack/os_ironic.py
index 0954868a7b..2658203646 100644
--- a/lib/ansible/modules/cloud/openstack/os_ironic.py
+++ b/lib/ansible/modules/cloud/openstack/os_ironic.py
@@ -32,6 +32,7 @@ DOCUMENTATION = '''
 module: os_ironic
 short_description: Create/Delete Bare Metal Resources from OpenStack
 extends_documentation_fragment: openstack
+author: "Monty Taylor (@emonty)"
 version_added: "2.0"
 description:
     - Create or Remove Ironic nodes from OpenStack.
@@ -75,28 +76,30 @@ options:
         - Information for this server's driver. Will vary based on which
           driver is in use. Any sub-field which is populated will be validated
           during creation.
+      suboptions:
         power:
-          - Information necessary to turn this server on / off. This often
-            includes such things as IPMI username, password, and IP address.
+            description:
+                - Information necessary to turn this server on / off.
+                  This often includes such things as IPMI username, password, and IP address.
           required: true
         deploy:
-          - Information necessary to deploy this server directly, without
-            using Nova. THIS IS NOT RECOMMENDED.
+            description:
+                - Information necessary to deploy this server directly, without using Nova. THIS IS NOT RECOMMENDED.
         console:
-          - Information necessary to connect to this server's serial console.
-            Not all drivers support this.
+            description:
+                - Information necessary to connect to this server's serial console.  Not all drivers support this.
         management:
-          - Information necessary to interact with this server's management
-            interface. May be shared by power_info in some cases.
+            description:
+                - Information necessary to interact with this server's management interface. May be shared by power_info in some cases.
       required: true
     nics:
       description:
-        - A list of network interface cards, eg, " - mac: aa:bb:cc:aa:bb:cc"
+        - 'A list of network interface cards, eg, " - mac: aa:bb:cc:aa:bb:cc"'
       required: true
     properties:
       description:
-        - Definition of the physical characteristics of this server, used for
-          scheduling purposes
+        - Definition of the physical characteristics of this server, used for scheduling purposes
+      suboptions:
         cpu_arch:
           description:
             - CPU architecture (x86_64, i686, ...)
@@ -111,8 +114,7 @@ options:
           default: 1
         disk_size:
           description:
-            - size of first storage device in this machine (typically
-              /dev/sda), in GB
+            - size of first storage device in this machine (typically /dev/sda), in GB
           default: 1
     skip_update_of_driver_password:
       description:
diff --git a/lib/ansible/modules/cloud/openstack/os_ironic_node.py b/lib/ansible/modules/cloud/openstack/os_ironic_node.py
index 34e1c98a2b..fa41d6fcbc 100644
--- a/lib/ansible/modules/cloud/openstack/os_ironic_node.py
+++ b/lib/ansible/modules/cloud/openstack/os_ironic_node.py
@@ -32,7 +32,9 @@ DOCUMENTATION = '''
 ---
 module: os_ironic_node
 short_description: Activate/Deactivate Bare Metal Resources from OpenStack
+author: "Monty Taylor (@emonty)"
 extends_documentation_fragment: openstack
+version_added: "2.0"
 description:
     - Deploy to nodes controlled by Ironic.
 options:
@@ -71,6 +73,7 @@ options:
         - Definition of the instance information which is used to deploy
           the node.  This information is only required when an instance is
           set to present.
+      suboptions:
         image_source:
           description:
             - An HTTP(S) URL where the image can be retrieved from.
diff --git a/lib/ansible/modules/cloud/openstack/os_object.py b/lib/ansible/modules/cloud/openstack/os_object.py
index d1a9b9d9da..9e67ab39df 100644
--- a/lib/ansible/modules/cloud/openstack/os_object.py
+++ b/lib/ansible/modules/cloud/openstack/os_object.py
@@ -31,7 +31,8 @@ DOCUMENTATION = '''
 ---
 module: os_object
 short_description: Create or Delete objects and containers from OpenStack
-version_added: "1.10"
+version_added: "2.0"
+author: "Monty Taylor (@emonty)"
 extends_documentation_fragment: openstack
 description:
    - Create or Delete objects and containers from OpenStack
@@ -60,7 +61,6 @@ options:
        - Should the resource be present or absent.
      choices: [present, absent]
      default: present
-requirements: ["shade"]
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/cloud/openstack/os_security_group.py b/lib/ansible/modules/cloud/openstack/os_security_group.py
index 3fb3d05f16..3ed5dfceb7 100644
--- a/lib/ansible/modules/cloud/openstack/os_security_group.py
+++ b/lib/ansible/modules/cloud/openstack/os_security_group.py
@@ -32,6 +32,7 @@ DOCUMENTATION = '''
 module: os_security_group
 short_description: Add/Delete security groups from an OpenStack cloud.
 extends_documentation_fragment: openstack
+author: "Monty Taylor (@emonty)"
 version_added: "2.0"
 description:
    - Add or Remove security groups from an OpenStack cloud.
diff --git a/lib/ansible/modules/cloud/openstack/os_security_group_rule.py b/lib/ansible/modules/cloud/openstack/os_security_group_rule.py
index 86258255b4..3379d16040 100644
--- a/lib/ansible/modules/cloud/openstack/os_security_group_rule.py
+++ b/lib/ansible/modules/cloud/openstack/os_security_group_rule.py
@@ -32,7 +32,7 @@ DOCUMENTATION = '''
 module: os_security_group_rule
 short_description: Add/Delete rule from an existing security group
 extends_documentation_fragment: openstack
-version_added: "1.10"
+version_added: "2.0"
 description:
    - Add or Remove rule from an existing security group
 options:
@@ -81,7 +81,6 @@ options:
        - Should the resource be present or absent.
      choices: [present, absent]
      default: present
-
 requirements: ["shade"]
 '''
 
@@ -257,7 +256,6 @@ def _system_state_change(module, secgroup, remotegroup):
 
 
 def main():
-
     argument_spec = openstack_full_argument_spec(
         security_group   = dict(required=True),
         # NOTE(Shrews): None is an acceptable protocol value for
diff --git a/lib/ansible/modules/cloud/openstack/os_server.py b/lib/ansible/modules/cloud/openstack/os_server.py
index c732189e18..0bb7dbcfbc 100644
--- a/lib/ansible/modules/cloud/openstack/os_server.py
+++ b/lib/ansible/modules/cloud/openstack/os_server.py
@@ -45,12 +45,10 @@ options:
      description:
         - Name that has to be given to the instance
      required: true
-     default: None
    image:
      description:
         - The name or id of the base image to boot.
      required: true
-     default: None
    image_exclude:
      description:
         - Text to use to filter image names, for the case, such as HP, where
@@ -110,7 +108,7 @@ options:
      default: 'yes'
      aliases: ['auto_floating_ip', 'public_ip']
    floating_ips:
-     decription:
+     description:
         - list of valid floating IPs that pre-exist to assign to this node
      required: false
      default: None
@@ -648,4 +646,5 @@ def main():
 # this is magic, see lib/ansible/module_common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
diff --git a/lib/ansible/modules/cloud/openstack/os_server_volume.py b/lib/ansible/modules/cloud/openstack/os_server_volume.py
index 4fb4dde2ce..a6549649d8 100644
--- a/lib/ansible/modules/cloud/openstack/os_server_volume.py
+++ b/lib/ansible/modules/cloud/openstack/os_server_volume.py
@@ -44,11 +44,11 @@ options:
        - Should the resource be present or absent.
      choices: [present, absent]
      default: present
+     required: false
    server:
      description:
        - Name or ID of server you want to attach a volume to
      required: true
-     default: None
    volume:
      description:
       - Name or id of volume you want to attach to a server
@@ -58,7 +58,9 @@ options:
       - Device you want to attach. Defaults to auto finding a device name.
      required: false
      default: None
-requirements: ["shade"]
+requirements:
+    - "python >= 2.6"
+    - "shade"
 '''
 
 EXAMPLES = '''
@@ -153,4 +155,5 @@ def main():
 # this is magic, see lib/ansible/module_utils/common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
diff --git a/lib/ansible/modules/cloud/openstack/os_volume.py b/lib/ansible/modules/cloud/openstack/os_volume.py
index 024a8d9826..6d6cc08d74 100644
--- a/lib/ansible/modules/cloud/openstack/os_volume.py
+++ b/lib/ansible/modules/cloud/openstack/os_volume.py
@@ -47,7 +47,6 @@ options:
      description:
         - Name of volume
      required: true
-     default: None
    display_description:
      description:
        - String describing the volume
@@ -59,7 +58,7 @@ options:
      required: false
      default: None
    image:
-     descritpion:
+     description:
        - Image name or id for boot from volume
      required: false
      default: None
@@ -73,7 +72,9 @@ options:
        - Should the resource be present or absent.
      choices: [present, absent]
      default: present
-requirements: ["shade"]
+requirements:
+     - "python >= 2.6"
+     - "shade"
 '''
 
 EXAMPLES = '''
@@ -162,4 +163,5 @@ def main():
 # this is magic, see lib/ansible/module_common.py
 from ansible.module_utils.basic import *
 from ansible.module_utils.openstack import *
-main()
+if __name__ == '__main__':
+    main()
diff --git a/lib/ansible/modules/cloud/rackspace/rax_scaling_group.py b/lib/ansible/modules/cloud/rackspace/rax_scaling_group.py
index d1f3eeaca0..95aef91cc5 100644
--- a/lib/ansible/modules/cloud/rackspace/rax_scaling_group.py
+++ b/lib/ansible/modules/cloud/rackspace/rax_scaling_group.py
@@ -109,7 +109,7 @@ options:
       - Data to be uploaded to the servers config drive. This option implies
         I(config_drive). Can be a file path or a string
     version_added: 1.8
-  wait
+  wait:
     description:
       - wait for the scaling group to finish provisioning the minimum amount of
         servers
@@ -121,7 +121,7 @@ options:
     description:
       - how long before wait gives up, in seconds
     default: 300
-author: Matt Martz
+author: "Matt Martz (@sivel)"
 extends_documentation_fragment: rackspace
 '''
 
diff --git a/lib/ansible/modules/cloud/vmware/vsphere_guest.py b/lib/ansible/modules/cloud/vmware/vsphere_guest.py
index e54465e891..5425db6f89 100644
--- a/lib/ansible/modules/cloud/vmware/vsphere_guest.py
+++ b/lib/ansible/modules/cloud/vmware/vsphere_guest.py
@@ -203,6 +203,10 @@ EXAMPLES = '''
         type: vmxnet3
         network: VM Network
         network_type: standard
+      nic2:
+        type: vmxnet3
+        network: dvSwitch Network
+        network_type: dvs
     vm_hardware:
       memory_mb: 2048
       num_cpus: 2
@@ -251,7 +255,6 @@ EXAMPLES = '''
       hostname: esx001.mydomain.local
 
 # Deploy a guest from a template
-# No reconfiguration of the destination guest is done at this stage, a reconfigure would be needed to adjust memory/cpu etc..
 - vsphere_guest:
     vcenter_hostname: vcenter.mydomain.local
     username: myuser
diff --git a/lib/ansible/modules/commands/command.py b/lib/ansible/modules/commands/command.py
index 2c04a3b21e..9b8afe3ef5 100644
--- a/lib/ansible/modules/commands/command.py
+++ b/lib/ansible/modules/commands/command.py
@@ -26,7 +26,6 @@ ANSIBLE_METADATA = {'status': ['stableinterface'],
 DOCUMENTATION = '''
 ---
 module: command
-version_added: historical
 short_description: Executes a command on a remote node
 version_added: historical
 description:
@@ -42,7 +41,6 @@ options:
         See the examples!
     required: true
     default: null
-    aliases: []
   creates:
     description:
       - a filename or (since 2.0) glob pattern, when it already exists, this step will B(not) be run.
diff --git a/lib/ansible/modules/commands/raw.py b/lib/ansible/modules/commands/raw.py
index 41d677df68..e76cf42bc7 100644
--- a/lib/ansible/modules/commands/raw.py
+++ b/lib/ansible/modules/commands/raw.py
@@ -22,7 +22,6 @@ ANSIBLE_METADATA = {'status': ['stableinterface'],
 DOCUMENTATION = '''
 ---
 module: raw
-version_added: historical
 short_description: Executes a low-down and dirty SSH command
 version_added: historical
 options:
diff --git a/lib/ansible/modules/database/mysql/mysql_user.py b/lib/ansible/modules/database/mysql/mysql_user.py
index d3c3c5f3f1..286106fe71 100644
--- a/lib/ansible/modules/database/mysql/mysql_user.py
+++ b/lib/ansible/modules/database/mysql/mysql_user.py
@@ -98,7 +98,7 @@ options:
     required: false
     default: always
     choices: ['always', 'on_create']
-    version_added: "1.9"
+    version_added: "2.0"
     description:
       - C(always) will update passwords if they differ.  C(on_create) will only set the password for newly created users.
 notes:
@@ -301,13 +301,6 @@ def user_mod(cursor, user, host, host_all, password, encrypted, new_priv, append
     changed = False
     grant_option = False
 
-    # Handle clear text and hashed passwords.
-    if bool(password):
-        # Determine what user management method server uses
-        old_user_mgmt = server_version_check(cursor)
-
-    # to simplify code, if we have a specific host and no host_all, we create
-    # a list with just host and loop over that
     if host_all:
         hostnames = user_get_hostnames(cursor, [user])
     else:
@@ -348,7 +341,7 @@ def user_mod(cursor, user, host, host_all, password, encrypted, new_priv, append
                     if module.check_mode:
                         return True
                     if old_user_mgmt:
-                        cursor.execute("SET PASSWORD FOR %s@%s = %s", (user, host, password))
+                        cursor.execute("SET PASSWORD FOR %s@%s = PASSWORD(%s)", (user, host, password))
                     else:
                         cursor.execute("ALTER USER %s@%s IDENTIFIED WITH mysql_native_password BY %s", (user, host, password))
                     changed = True
@@ -614,7 +607,7 @@ def main():
             module.fail_json(msg="invalid privileges string: %s" % str(e))
 
     if state == "present":
-        if user_exists(cursor, user, host):
+        if user_exists(cursor, user, host, host_all):
             try:
                 if update_password == 'always':
                     changed = user_mod(cursor, user, host, host_all, password, encrypted, priv, append_privs, module)
diff --git a/lib/ansible/modules/database/postgresql/postgresql_user.py b/lib/ansible/modules/database/postgresql/postgresql_user.py
index dfe7a790f3..95c19caaba 100644
--- a/lib/ansible/modules/database/postgresql/postgresql_user.py
+++ b/lib/ansible/modules/database/postgresql/postgresql_user.py
@@ -349,12 +349,21 @@ def user_delete(cursor, user):
     cursor.execute("RELEASE SAVEPOINT ansible_pgsql_user_delete")
     return True
 
-def has_table_privilege(cursor, user, table, priv):
-    if priv == 'ALL':
-        priv = ','.join([ p for p in VALID_PRIVS['table'] if p != 'ALL' ])
-    query = 'SELECT has_table_privilege(%s, %s, %s)'
-    cursor.execute(query, (user, table, priv))
-    return cursor.fetchone()[0]
+def has_table_privileges(cursor, user, table, privs):
+    """
+    Return the difference between the privileges that a user already has and
+    the privileges that they desire to have.
+
+    :returns: tuple of:
+        * privileges that they have and were requested
+        * privileges they currently hold but were not requested
+        * privileges requested that they do not hold
+    """
+    cur_privs = get_table_privileges(cursor, user, table)
+    have_currently = cur_privs.intersection(privs)
+    other_current = cur_privs.difference(privs)
+    desired = privs.difference(cur_privs)
+    return (have_currently, other_current, desired)
 
 def get_table_privileges(cursor, user, table):
     if '.' in table:
@@ -364,26 +373,21 @@ def get_table_privileges(cursor, user, table):
     query = '''SELECT privilege_type FROM information_schema.role_table_grants
     WHERE grantee=%s AND table_name=%s AND table_schema=%s'''
     cursor.execute(query, (user, table, schema))
-    return set([x[0] for x in cursor.fetchall()])
+    return frozenset([x[0] for x in cursor.fetchall()])
 
-def grant_table_privilege(cursor, user, table, priv):
+def grant_table_privileges(cursor, user, table, privs):
     # Note: priv escaped by parse_privs
-    prev_priv = get_table_privileges(cursor, user, table)
+    privs = ', '.join(privs)
     query = 'GRANT %s ON TABLE %s TO %s' % (
-        priv, pg_quote_identifier(table, 'table'), pg_quote_identifier(user, 'role') )
+        privs, pg_quote_identifier(table, 'table'), pg_quote_identifier(user, 'role') )
     cursor.execute(query)
-    curr_priv = get_table_privileges(cursor, user, table)
-    return len(curr_priv) > len(prev_priv)
 
-def revoke_table_privilege(cursor, user, table, priv):
+def revoke_table_privileges(cursor, user, table, privs):
     # Note: priv escaped by parse_privs
-    prev_priv = get_table_privileges(cursor, user, table)
+    privs = ', '.join(privs)
     query = 'REVOKE %s ON TABLE %s FROM %s' % (
-        priv, pg_quote_identifier(table, 'table'), pg_quote_identifier(user, 'role') )
+        privs, pg_quote_identifier(table, 'table'), pg_quote_identifier(user, 'role') )
     cursor.execute(query)
-    curr_priv = get_table_privileges(cursor, user, table)
-    return len(curr_priv) < len(prev_priv)
-
 
 def get_database_privileges(cursor, user, db):
     priv_map = {
@@ -395,54 +399,62 @@ def get_database_privileges(cursor, user, db):
     cursor.execute(query, (db,))
     datacl = cursor.fetchone()[0]
     if datacl is None:
-        return []
+        return set()
     r = re.search('%s=(C?T?c?)/[a-z]+\,?' % user, datacl)
     if r is None:
-        return []
-    o = []
+        return set()
+    o = set()
     for v in r.group(1):
-        o.append(priv_map[v])
-    return o
+        o.add(priv_map[v])
+    return normalize_privileges(o, 'database')
 
-def has_database_privilege(cursor, user, db, priv):
-    if priv == 'ALL':
-        priv = ','.join([ p for p in VALID_PRIVS['database'] if p != 'ALL' ])
-    query = 'SELECT has_database_privilege(%s, %s, %s)'
-    cursor.execute(query, (user, db, priv))
-    return cursor.fetchone()[0]
+def has_database_privileges(cursor, user, db, privs):
+    """
+    Return the difference between the privileges that a user already has and
+    the privileges that they desire to have.
 
-def grant_database_privilege(cursor, user, db, priv):
+    :returns: tuple of:
+        * privileges that they have and were requested
+        * privileges they currently hold but were not requested
+        * privileges requested that they do not hold
+    """
+    cur_privs = get_database_privileges(cursor, user, db)
+    have_currently = cur_privs.intersection(privs)
+    other_current = cur_privs.difference(privs)
+    desired = privs.difference(cur_privs)
+    return (have_currently, other_current, desired)
+
+def grant_database_privileges(cursor, user, db, privs):
     # Note: priv escaped by parse_privs
-    prev_priv = get_database_privileges(cursor, user, db)
+    privs =', '.join(privs)
     if user == "PUBLIC":
         query = 'GRANT %s ON DATABASE %s TO PUBLIC' % (
-                priv, pg_quote_identifier(db, 'database'))
+                privs, pg_quote_identifier(db, 'database'))
     else:
         query = 'GRANT %s ON DATABASE %s TO %s' % (
-                priv, pg_quote_identifier(db, 'database'),
+                privs, pg_quote_identifier(db, 'database'),
                 pg_quote_identifier(user, 'role'))
     cursor.execute(query)
-    curr_priv = get_database_privileges(cursor, user, db)
-    return len(curr_priv) > len(prev_priv)
 
-def revoke_database_privilege(cursor, user, db, priv):
+def revoke_database_privileges(cursor, user, db, privs):
     # Note: priv escaped by parse_privs
-    prev_priv = get_database_privileges(cursor, user, db)
+    privs = ', '.join(privs)
     if user == "PUBLIC":
         query = 'REVOKE %s ON DATABASE %s FROM PUBLIC' % (
-                priv, pg_quote_identifier(db, 'database'))
+                privs, pg_quote_identifier(db, 'database'))
     else:
         query = 'REVOKE %s ON DATABASE %s FROM %s' % (
-                priv, pg_quote_identifier(db, 'database'),
+                privs, pg_quote_identifier(db, 'database'),
                 pg_quote_identifier(user, 'role'))
     cursor.execute(query)
-    curr_priv = get_database_privileges(cursor, user, db)
-    return len(curr_priv) < len(prev_priv)
 
 def revoke_privileges(cursor, user, privs):
     if privs is None:
         return False
 
+    revoke_funcs = dict(table=revoke_table_privileges, database=revoke_database_privileges)
+    check_funcs = dict(table=has_table_privileges, database=has_database_privileges)
+
     changed = False
     for type_ in privs:
         for name, privileges in iteritems(privs[type_]):
@@ -498,6 +510,17 @@ def parse_role_attrs(role_attr_flags):
     o_flags = ' '.join(flag_set)
     return o_flags
 
+def normalize_privileges(privs, type_):
+    new_privs = set(privs)
+    if 'ALL' in new_privs:
+        new_privs.update(VALID_PRIVS[type_])
+        new_privs.remove('ALL')
+    if 'TEMP' in new_privs:
+        new_privs.add('TEMPORARY')
+        new_privs.remove('TEMP')
+
+    return new_privs
+
 def parse_privs(privs, db):
     """
     Parse privilege string to determine permissions for database db.
@@ -530,6 +553,8 @@ def parse_privs(privs, db):
         if not priv_set.issubset(VALID_PRIVS[type_]):
             raise InvalidPrivsError('Invalid privs specified for %s: %s' %
                 (type_, ' '.join(priv_set.difference(VALID_PRIVS[type_]))))
+
+        priv_set = normalize_privileges(priv_set, type_)
         o_privs[type_][name] = priv_set
 
     return o_privs
diff --git a/lib/ansible/modules/files/assemble.py b/lib/ansible/modules/files/assemble.py
index 2895b00700..41e7530e44 100644
--- a/lib/ansible/modules/files/assemble.py
+++ b/lib/ansible/modules/files/assemble.py
@@ -90,9 +90,11 @@ options:
         validate is passed in via '%s' which must be present as in the sshd example below.
         The command is passed securely so shell features like expansion and pipes won't work.
     required: false
-    default: ""
+    default: null
+    version_added: "2.0"
 author: "Stephen Fromm (@sfromm)"
-extends_documentation_fragment: files
+extends_documentation_fragment:
+    - files
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/files/ini_file.py b/lib/ansible/modules/files/ini_file.py
index e04b79e9bf..f9f08ac569 100644
--- a/lib/ansible/modules/files/ini_file.py
+++ b/lib/ansible/modules/files/ini_file.py
@@ -33,8 +33,7 @@ description:
      - Manage (add, remove, change) individual settings in an INI-style file without having
        to manage the file as a whole with, say, M(template) or M(assemble). Adds missing
        sections if they don't exist.
-     - Comments are discarded when the source file is read, and therefore will not
-       show up in the destination file.
+     - Before version 2.0, comments are discarded when the source file is read, and therefore will not show up in the destination file.
 version_added: "0.9"
 options:
   dest:
diff --git a/lib/ansible/modules/files/lineinfile.py b/lib/ansible/modules/files/lineinfile.py
index 28c3d8e90a..0e55bc9da5 100644
--- a/lib/ansible/modules/files/lineinfile.py
+++ b/lib/ansible/modules/files/lineinfile.py
@@ -29,8 +29,9 @@ module: lineinfile
 author: 
     - "Daniel Hokka Zakrissoni (@dhozac)"
     - "Ahti Kitsik (@ahtik)"
-extends_documentation_fragment: files
-extends_documentation_fragment: validate
+extends_documentation_fragment:
+    - files
+    - validate
 short_description: Ensure a particular line is in a file, or replace an
                    existing line using a back-referenced regular expression.
 description:
diff --git a/lib/ansible/modules/files/replace.py b/lib/ansible/modules/files/replace.py
index 7e8d5e45d1..85d6d91e1f 100644
--- a/lib/ansible/modules/files/replace.py
+++ b/lib/ansible/modules/files/replace.py
@@ -30,8 +30,9 @@ DOCUMENTATION = """
 ---
 module: replace
 author: "Evan Kaufman (@EvanK)"
-extends_documentation_fragment: files
-extends_documentation_fragment: validate
+extends_documentation_fragment:
+    - files
+    - validate
 short_description: Replace all instances of a particular string in a
                    file using a back-referenced regular expression.
 description:
diff --git a/lib/ansible/modules/files/template.py b/lib/ansible/modules/files/template.py
index 8152e0cb3a..4727eff774 100644
--- a/lib/ansible/modules/files/template.py
+++ b/lib/ansible/modules/files/template.py
@@ -43,13 +43,10 @@ options:
     description:
       - Path of a Jinja2 formatted template on the Ansible controller. This can be a relative or absolute path.
     required: true
-    default: null
-    aliases: []
   dest:
     description:
       - Location to render the template to on the remote machine.
     required: true
-    default: null
   backup:
     description:
       - Create a backup file including the timestamp information so you can get
@@ -77,8 +74,9 @@ notes:
 author:
     - Ansible Core Team 
     - Michael DeHaan
-extends_documentation_fragment: files
-extends_documentation_fragment: validate
+extends_documentation_fragment:
+    - files
+    - validate
 '''
 
 EXAMPLES = '''
diff --git a/lib/ansible/modules/network/basics/get_url.py b/lib/ansible/modules/network/basics/get_url.py
index 0d9d81fd36..a15b78df4f 100644
--- a/lib/ansible/modules/network/basics/get_url.py
+++ b/lib/ansible/modules/network/basics/get_url.py
@@ -86,6 +86,7 @@ options:
     required: false
     choices: [ "yes", "no" ]
     default: "no"
+    version_added: '2.1'
   sha256sum:
     description:
       - If a SHA-256 checksum is passed to this parameter, the digest of the
diff --git a/lib/ansible/modules/network/basics/uri.py b/lib/ansible/modules/network/basics/uri.py
index 889cc4f151..24257dc356 100644
--- a/lib/ansible/modules/network/basics/uri.py
+++ b/lib/ansible/modules/network/basics/uri.py
@@ -66,6 +66,7 @@ options:
       - The serialization format of the body. When set to json, encodes the
         body argument, if needed, and automatically sets the Content-Type header accordingly.
     required: false
+    choices: [ "raw", "json" ]
     default: raw
     version_added: "2.0"
   method:
diff --git a/lib/ansible/modules/network/junos/junos_config.py b/lib/ansible/modules/network/junos/junos_config.py
index b0c0252c7b..a1212e974c 100644
--- a/lib/ansible/modules/network/junos/junos_config.py
+++ b/lib/ansible/modules/network/junos/junos_config.py
@@ -72,14 +72,11 @@ options:
     default: null
   zeroize:
     description:
-      - The C(zeroize) argument is used to completely santaize the
+      - The C(zeroize) argument is used to completely sanitize the
         remote device configuration back to initial defaults.  This
         argument will effectively remove all current configuration
         statements on the remote device.
     required: false
-    choices:
-        - yes
-        - no
     default: null
   confirm:
     description:
diff --git a/lib/ansible/modules/network/nxos/nxos_acl.py b/lib/ansible/modules/network/nxos/nxos_acl.py
index 7683d1aada..ce1a19e018 100644
--- a/lib/ansible/modules/network/nxos/nxos_acl.py
+++ b/lib/ansible/modules/network/nxos/nxos_acl.py
@@ -32,14 +32,14 @@ author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
 notes:
-    - I(state)=absent removes the ACE if it exists
-    - I(state)=delete_acl deleted the ACL if it exists
-    - for idempotency, use port numbers for the src/dest port
+    - C(state=absent) removes the ACE if it exists.
+    - C(state=delete_acl) deleted the ACL if it exists.
+    - For idempotency, use port numbers for the src/dest port
       params like I(src_port1) and names for the well defined protocols
       for the I(proto) param.
-    - while this module is idempotent in that if the ace as presented in the
-      task is identical to the one on the switch, no changes will be made. If
-      there is any difference, what is in Ansible will be pushed (configured
+    - Although this module is idempotent in that if the ace as presented in
+      the task is identical to the one on the switch, no changes will be made.
+      If there is any difference, what is in Ansible will be pushed (configured
       options will be overridden).  This is to improve security, but at the
       same time remember an ACE is removed, then re-added, so if there is a
       change, the new ACE will be exactly what parameters you are sending to
@@ -47,151 +47,152 @@ notes:
 options:
     seq:
         description:
-            - sequence number of the entry (ACE)
+            - Sequence number of the entry (ACE).
         required: false
         default: null
     name:
         description:
-            - Case sensitive name of the access list (ACL)
+            - Case sensitive name of the access list (ACL).
         required: true
     action:
         description:
-            - action of the ACE
+            - Action of the ACE.
         required: false
         default: null
         choices: ['permit', 'deny', 'remark']
     remark:
         description:
-            - If action is set to remark, this is the description
+            - If action is set to remark, this is the description.
         required: false
         default: null
     proto:
         description:
-            - port number or protocol (as supported by the switch)
+            - Port number or protocol (as supported by the switch).
         required: false
         default: null
     src:
         description:
-            - src ip and mask using IP/MASK notation and supports keyword 'any'
+            - Source ip and mask using IP/MASK notation and
+              supports keyword 'any'.
         required: false
         default: null
     src_port_op:
         description:
-            - src port operands such as eq, neq, gt, lt, range
+            - Source port operands such as eq, neq, gt, lt, range.
         required: false
         default: null
         choices: ['any', 'eq', 'gt', 'lt', 'neq', 'range']
     src_port1:
         description:
-            - port/protocol and also first (lower) port when using range
-              operand
+            - Port/protocol and also first (lower) port when using range
+              operand.
         required: false
         default: null
     src_port2:
         description:
-            - second (end) port when using range operand
+            - Second (end) port when using range operand.
         required: false
         default: null
     dest:
         description:
-            - dest ip and mask using IP/MASK notation and supports the
-              keyword 'any'
+            - Destination ip and mask using IP/MASK notation and supports the
+              keyword 'any'.
         required: false
         default: null
     dest_port_op:
         description:
-            - dest port operands such as eq, neq, gt, lt, range
+            - Destination port operands such as eq, neq, gt, lt, range.
         required: false
         default: null
         choices: ['any', 'eq', 'gt', 'lt', 'neq', 'range']
     dest_port1:
         description:
-            - port/protocol and also first (lower) port when using range
-              operand
+            - Port/protocol and also first (lower) port when using range
+              operand.
         required: false
         default: null
     dest_port2:
         description:
-            - second (end) port when using range operand
+            - Second (end) port when using range operand.
         required: false
         default: null
     log:
         description:
-            - Log matches against this entry
+            - Log matches against this entry.
         required: false
         default: null
         choices: ['enable']
     urg:
         description:
-            - Match on the URG bit
+            - Match on the URG bit.
         required: false
         default: null
         choices: ['enable']
     ack:
         description:
-            - Match on the ACK bit
+            - Match on the ACK bit.
         required: false
         default: null
         choices: ['enable']
     psh:
         description:
-            - Match on the PSH bit
+            - Match on the PSH bit.
         required: false
         default: null
         choices: ['enable']
     rst:
         description:
-            - Match on the RST bit
+            - Match on the RST bit.
         required: false
         default: null
         choices: ['enable']
     syn:
         description:
-            - Match on the SYN bit
+            - Match on the SYN bit.
         required: false
         default: null
         choices: ['enable']
     fin:
         description:
-            - Match on the FIN bit
+            - Match on the FIN bit.
         required: false
         default: null
         choices: ['enable']
     established:
         description:
-            - Match established connections
+            - Match established connections.
         required: false
         default: null
         choices: ['enable']
     fragments:
         description:
-            - Check non-initial fragments
+            - Check non-initial fragments.
         required: false
         default: null
         choices: ['enable']
     time-range:
         description:
-            - Name of time-range to apply
+            - Name of time-range to apply.
         required: false
         default: null
     precedence:
         description:
-            - Match packets with given precedence
+            - Match packets with given precedence.
         required: false
         default: null
         choices: ['critical', 'flash', 'flash-override', 'immediate',
                   'internet', 'network', 'priority', 'routine']
     dscp:
         description:
-            - Match packets with given dscp value
+            - Match packets with given dscp value.
         required: false
         default: null
-        choices: ['af11, 'af12, 'af13, 'af21', 'af22', 'af23','af31','af32',
+        choices: ['af11', 'af12', 'af13', 'af21', 'af22', 'af23','af31','af32',
                   'af33', 'af41', 'af42', 'af43', 'cs1', 'cs2', 'cs3', 'cs4',
                   'cs5', 'cs6', 'cs7', 'default', 'ef']
     state:
         description:
-            - Specify desired state of the resource
+            - Specify desired state of the resource.
         required: false
         default: present
         choices: ['present','absent','delete_acl']
@@ -220,6 +221,7 @@ proposed:
             "proto": "tcp", "seq": "10", "src": "1.1.1.1/24"}
 existing:
     description: k/v pairs of existing ACL entries.
+    returned: always
     type: dict
     sample: {}
 end_state:
@@ -240,217 +242,32 @@ changed:
     sample: true
 '''
 
-
-# COMMON CODE FOR MIGRATION
-
-import re
-import time
 import collections
-import itertools
-import shlex
 import json
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -462,14 +279,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -477,93 +286,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -615,303 +354,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -919,6 +399,7 @@ def load_config(module, candidate):
     return result
 # END OF COMMON CODE
 
+
 def get_cli_body_ssh(command, response, module):
     """Get response for when transport=cli.  This is kind of a hack and mainly
     needed because these modules were originally written for NX-API.  And
@@ -941,6 +422,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -1195,9 +681,11 @@ def main():
             host=dict(required=True),
             username=dict(type='str'),
             password=dict(no_log=True, type='str'),
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     state = module.params['state']
diff --git a/lib/ansible/modules/network/nxos/nxos_acl_interface.py b/lib/ansible/modules/network/nxos/nxos_acl_interface.py
index 837ea61317..739f55c044 100644
--- a/lib/ansible/modules/network/nxos/nxos_acl_interface.py
+++ b/lib/ansible/modules/network/nxos/nxos_acl_interface.py
@@ -88,11 +88,6 @@ acl_applied_to:
     type: list
     sample: [{"acl_type": "Router ACL", "direction": "egress",
             "interface": "Ethernet1/41", "name": "ANSIBLE"}]
-state:
-    description: state as sent in from the playbook
-    returned: always
-    type: string
-    sample: "present"
 updates:
     description: commands sent to the device
     returned: always
@@ -105,211 +100,32 @@ changed:
     sample: true
 '''
 
-# COMMON CODE FOR MIGRATION
-
-import re
-import time
 import collections
-import itertools
-import shlex
-import itertools
+import json
 
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
+# COMMON CODE FOR MIGRATION
+import re
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
 
-class ConfigLine(object):
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
 
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -321,14 +137,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -336,93 +144,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -474,18 +212,20 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
+def get_network_module(**kwargs):
+    try:
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-def get_config(module):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
+        try:
         config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
@@ -494,15 +234,22 @@ def load_config(module, candidate):
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -511,6 +258,7 @@ def load_config(module, candidate):
 # END OF COMMON CODE
 
 
+
 def get_cli_body_ssh(command, response, module):
     """Get response for when transport=cli.  This is kind of a hack and mainly
     needed because these modules were originally written for NX-API.  And
@@ -533,6 +281,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -542,6 +295,19 @@ def execute_show(cmds, module, command_type=None):
         clie = get_exception()
         module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
+    except AttributeError:
+        try:
+            if command_type:
+                command_type = command_type_map.get(command_type)
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+            else:
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+        except ShellError:
+            clie = get_exception()
+            module.fail_json(msg='Error sending {0}'.format(cmds),
+                             error=str(clie))
     return response
 
 
@@ -705,9 +471,11 @@ def main():
             direction=dict(required=True, choices=['egress', 'ingress']),
             state=dict(choices=['absent', 'present'],
                        default='present'),
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     state = module.params['state']
@@ -763,7 +531,6 @@ def main():
     results = {}
     results['proposed'] = proposed
     results['existing'] = existing
-    results['state'] = state
     results['updates'] = cmds
     results['changed'] = changed
     results['end_state'] = end_state
@@ -771,10 +538,6 @@ def main():
 
     module.exit_json(**results)
 
-from ansible.module_utils.basic import *
-from ansible.module_utils.urls import *
-from ansible.module_utils.shell import *
-from ansible.module_utils.netcfg import *
-from ansible.module_utils.nxos import *
+
 if __name__ == '__main__':
     main()
diff --git a/lib/ansible/modules/network/nxos/nxos_bgp.py b/lib/ansible/modules/network/nxos/nxos_bgp.py
index ce018fbc40..785e112253 100644
--- a/lib/ansible/modules/network/nxos/nxos_bgp.py
+++ b/lib/ansible/modules/network/nxos/nxos_bgp.py
@@ -24,17 +24,19 @@ DOCUMENTATION = '''
 ---
 module: nxos_bgp
 version_added: "2.2"
-short_description: Manages BGP configuration
+short_description: Manages BGP configuration.
 description:
-    - Manages BGP configurations on NX-OS switches
-author: Jason Edelman (@jedelman8), Gabriele Gerbino (@GGabriele)
+    - Manages BGP configurations on NX-OS switches.
+author:
+    - Jason Edelman (@jedelman8)
+    - Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - State 'absent' removes the whole BGP ASN configuration when VRF is
-      'default' or the whole VRF instance within the BGP process when using
-      a different VRF.
-    - 'default', when supported, restores params default value.
-    - Configuring global parmas is only permitted if VRF is 'default'.
+    - C(state=absent) removes the whole BGP ASN configuration when
+      C(vrf=default) or the whole VRF instance within the BGP process when
+      using a different VRF.
+    - Default when supported restores params default value.
+    - Configuring global parmas is only permitted if C(vrf=default).
 options:
     asn:
         description:
@@ -43,55 +45,58 @@ options:
         required: true
     vrf:
         description:
-            - Name of the VRF. The name 'default' is a valid VRF representing the global BGP.
+            - Name of the VRF. The name 'default' is a valid VRF representing
+              the global BGP.
         required: false
         default: null
     bestpath_always_compare_med:
         description:
-            - Enable/Disable MED comparison on paths from different autonomous systems.
+            - Enable/Disable MED comparison on paths from different
+              autonomous systems.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     bestpath_aspath_multipath_relax:
         description:
             - Enable/Disable load sharing across the providers with
               different (but equal-length) AS paths.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     bestpath_compare_routerid:
         description:
             - Enable/Disable comparison of router IDs for identical eBGP paths.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     bestpath_cost_community_ignore:
         description:
             - Enable/Disable Ignores the cost community for BGP best-path
               calculations.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     bestpath_med_confed:
         description:
             - Enable/Disable enforcement of bestpath to do a MED comparison
               only between paths originated within a confederation.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     bestpath_med_missing_as_worst:
         description:
-            - Enable/Disable assigns the value of infinity to received routes that
-              do not carry the MED attribute, making these routes the least desirable.
+            - Enable/Disable assigns the value of infinity to received
+              routes that do not carry the MED attribute, making these routes
+              the least desirable.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     bestpath_med_non_deterministic:
         description:
-            - Enable/Disable deterministic selection of the best MED path from among
-              the paths from the same autonomous system.
+            - Enable/Disable deterministic selection of the best MED pat
+              from among the paths from the same autonomous system.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     cluster_id:
         description:
@@ -110,27 +115,30 @@ options:
         default: null
     disable_policy_batching:
         description:
-            - Enable/Disable the batching evaluation of prefix advertisements to all peers.
+            - Enable/Disable the batching evaluation of prefix advertisement
+              to all peers.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     disable_policy_batching_ipv4_prefix_list:
         description:
-            - Enable/Disable the batching evaluation of prefix advertisements to all
-              peers with prefix list.
+            - Enable/Disable the batching evaluation of prefix advertisements
+              to all peers with prefix list.
         required: false
         default: null
     disable_policy_batching_ipv6_prefix_list:
         description:
-            - Enable/Disable the batching evaluation of prefix advertisements to all peers with prefix list.
+            - Enable/Disable the batching evaluation of prefix advertisements
+              to all peers with prefix list.
         required: false
     enforce_first_as:
         description:
-            - Enable/Disable enforces the neighbor autonomous system to be the first AS number
-              listed in the AS path attribute for eBGP.  On NX-OS, this property is only supported
-              in the global BGP context.
+            - Enable/Disable enforces the neighbor autonomous system to be
+              the first AS number listed in the AS path attribute for eBGP.
+              On NX-OS, this property is only supported in the
+              global BGP context.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     event_history_cli:
         description:
@@ -158,45 +166,48 @@ options:
     fast_external_fallover:
         description:
             - Enable/Disable immediately reset the session if the link to a
-              directly connected BGP peer goes down.  Only supported in the global BGP context.
+              directly connected BGP peer goes down.  Only supported in the
+              global BGP context.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     flush_routes:
         description:
             - Enable/Disable flush routes in RIB upon controlled restart.
-              On NX-OS, this property is only supported in the global BGP context.
+              On NX-OS, this property is only supported in the global
+              BGP context.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     graceful_restart:
         description:
             - Enable/Disable graceful restart.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     graceful_restart_helper:
         description:
             - Enable/Disable graceful restart helper mode.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     graceful_restart_timers_restart:
         description:
             - Set maximum time for a restart sent to the BGP peer.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     graceful_restart_timers_stalepath_time:
         description:
-            - Set maximum time that BGP keeps the stale routes from the restarting BGP peer.
-        choices: ['true','false', 'default']
+            - Set maximum time that BGP keeps the stale routes from the
+              restarting BGP peer.
+        choices: ['true','false']
         default: null
     isolate:
         description:
             - Enable/Disable isolate this router from BGP perspective.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     local_as:
         description:
@@ -207,23 +218,25 @@ options:
         description:
             - Enable/Disable message logging for neighbor up/down event.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     maxas_limit:
         description:
-            - Specify Maximum number of AS numbers allowed in the AS-path attribute
-              Valid values are between 1 and 512.
+            - Specify Maximum number of AS numbers allowed in the AS-path
+              attribute. Valid values are between 1 and 512.
         required: false
         default: null
     neighbor_down_fib_accelerate:
         description:
-            - Enable/Disable handle BGP neighbor down event, due to various reasons.
+            - Enable/Disable handle BGP neighbor down event, due to
+              various reasons.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     reconnect_interval:
         description:
-            - The BGP reconnection interval for dropped sessions.  1 - 60.
+            - The BGP reconnection interval for dropped sessions.
+              Valid values are between 1 and 60.
         required: false
         default: null
     router_id:
@@ -235,47 +248,44 @@ options:
         description:
             - Administratively shutdown the BGP protocol.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     suppress_fib_pending:
         description:
-            - Enable/Disable advertise only routes programmed in hardware to peers.
+            - Enable/Disable advertise only routes programmed in hardware
+              to peers.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     timer_bestpath_limit:
         description:
-            - Specify timeout for the first best path after a restart, in seconds.
+            - Specify timeout for the first best path after a restart,
+              in seconds.
         required: false
         default: null
     timer_bestpath_limit_always:
         description:
             - Enable/Disable update-delay-always option.
         required: false
-        choices: ['true','false', 'default']
+        choices: ['true','false']
         default: null
     timer_bgp_hold:
         description:
-            - Set bgp hold timer
+            - Set BGP hold timer.
         required: false
         default: null
     timer_bgp_keepalive:
         description:
-            - Set bgp keepalive timer.
+            - Set BGP keepalive timer.
         required: false
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 
 
@@ -294,11 +304,12 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"asn": "65535", "router_id": "1.1.1.1", "vrf": "test"}
 existing:
     description: k/v pairs of existing BGP configuration
+    returned: verbose mode
     type: dict
     sample: {"asn": "65535", "bestpath_always_compare_med": false,
             "bestpath_aspath_multipath_relax": false,
@@ -319,7 +330,7 @@ existing:
             "timer_bgp_keepalive": "60", "vrf": "test"}
 end_state:
     description: k/v pairs of BGP configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"asn": "65535", "bestpath_always_compare_med": false,
             "bestpath_aspath_multipath_relax": false,
@@ -351,12 +362,7 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
@@ -364,200 +370,17 @@ from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.network import NetworkModule
 from ansible.module_utils.shell import ShellError
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -569,14 +392,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -584,90 +399,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                string = item.text if ignore_whitespace is True else item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -719,303 +467,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -1204,7 +693,7 @@ def get_value(arg, config):
 
 def get_existing(module, args):
     existing = {}
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
 
     try:
         asn_regex = '.*router\sbgp\s(?P<existing_asn>\d+).*'
@@ -1219,7 +708,7 @@ def get_existing(module, args):
         if module.params['vrf'] != 'default':
             parents = [bgp_parent, 'vrf {0}'.format(module.params['vrf'])]
         else:
-            parents = bgp_parent
+            parents = [bgp_parent]
 
         config = netcfg.get_section(parents)
         if config:
@@ -1407,13 +896,13 @@ def main():
             timer_bestpath_limit=dict(required=False, type='str'),
             timer_bgp_hold=dict(required=False, type='str'),
             timer_bgp_keepalive=dict(required=False, type='str'),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         required_together=[['timer_bgp_hold',
                                             'timer_bgp_keepalive']],
                         supports_check_mode=True)
@@ -1507,7 +996,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_af.py b/lib/ansible/modules/network/nxos/nxos_bgp_af.py
index a24f8ee7e7..0181591bd5 100644
--- a/lib/ansible/modules/network/nxos/nxos_bgp_af.py
+++ b/lib/ansible/modules/network/nxos/nxos_bgp_af.py
@@ -24,14 +24,14 @@ DOCUMENTATION = '''
 ---
 module: nxos_bgp_af
 version_added: "2.2"
-short_description: Manages BGP Address-family configuration
+short_description: Manages BGP Address-family configuration.
 description:
-    - Manages BGP Address-family configurations on NX-OS switches
+    - Manages BGP Address-family configurations on NX-OS switches.
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - State 'absent' removes the whole BGP ASN configuration
-    - default, where supported, restores params default value
+    - C(state=absent) removes the whole BGP ASN configuration
+    - Default, where supported, restores params default value.
 options:
     asn:
         description:
@@ -45,7 +45,7 @@ options:
         required: true
     afi:
         description:
-            - Address Family Identifie.
+            - Address Family Identifier.
         required: true
         choices: ['ipv4','ipv6', 'vpnv4', 'vpnv6', 'l2vpn']
     safi:
@@ -56,7 +56,7 @@ options:
     additional_paths_install:
         description:
             - Install a backup path into the forwarding table and provide
-              prefix 'independent convergence (PIC) in case of a PE-CE link
+              prefix independent convergence (PIC) in case of a PE-CE link
               failure.
         required: false
         choices: ['true','false']
@@ -175,7 +175,7 @@ options:
               keyword which indicates that attributes should be copied from
               the aggregate. For example [['lax_inject_map', 'lax_exist_map'],
               ['nyc_inject_map', 'nyc_exist_map', 'copy-attributes'],
-              ['fsd_inject_map', 'fsd_exist_map']]
+              ['fsd_inject_map', 'fsd_exist_map']].
         required: false
         default: null
     maximum_paths:
@@ -194,9 +194,9 @@ options:
             - Networks to configure. Valid value is a list of network
               prefixes to advertise. The list must be in the form of an array.
               Each entry in the array must include a prefix address and an
-              optional route-map. Example: [['10.0.0.0/16', 'routemap_LA'],
+              optional route-map. For example [['10.0.0.0/16', 'routemap_LA'],
               ['192.168.1.1', 'Chicago'], ['192.168.2.0/24],
-              ['192.168.3.0/24', 'routemap_NYC']]
+              ['192.168.3.0/24', 'routemap_NYC']].
         required: false
         default: null
     next_hop_route_map:
@@ -213,7 +213,7 @@ options:
               redistribute from; the second entry defines a route-map name.
               A route-map is highly advised but may be optional on some
               platforms, in which case it may be omitted from the array list.
-              Example: [['direct', 'rm_direct'], ['lisp', 'rm_lisp']]
+              For example [['direct', 'rm_direct'], ['lisp', 'rm_lisp']].
         required: false
         default: null
     suppress_inactive:
@@ -237,16 +237,11 @@ options:
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 # configure a simple address-family
@@ -262,17 +257,18 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"advertise_l2vpn_evpn": true, "afi": "ipv4",
              "asn": "65535", "safi": "unicast", "vrf": "TESTING"}
 existing:
     description: k/v pairs of existing BGP AF configuration
+    returned: verbose mode
     type: dict
     sample: {}
 end_state:
     description: k/v pairs of BGP AF configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"additional_paths_install": false,
             "additional_paths_receive": false,
@@ -305,12 +301,7 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
@@ -319,200 +310,17 @@ from ansible.module_utils.network import NetworkModule
 from ansible.module_utils.shell import ShellError
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -524,14 +332,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -539,93 +339,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -677,303 +407,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -1213,7 +684,7 @@ def get_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
 
     try:
         asn_regex = '.*router\sbgp\s(?P<existing_asn>\d+).*'
@@ -1515,13 +986,13 @@ def main():
             suppress_inactive=dict(required=False, type='bool'),
             table_map=dict(required=False, type='str'),
             table_map_filter=dict(required=False, type='bool'),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         required_together=[DAMPENING_PARAMS,
                                           ['distance_ibgp',
                                            'distance_ebgp',
@@ -1624,7 +1095,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py
index 650258d92e..6d117b7c50 100644
--- a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py
+++ b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py
@@ -24,18 +24,18 @@ DOCUMENTATION = '''
 ---
 module: nxos_bgp_neighbor
 version_added: "2.2"
-short_description: Manages BGP neighbors configurations
+short_description: Manages BGP neighbors configurations.
 description:
-    - Manages BGP neighbors configurations on NX-OS switches
+    - Manages BGP neighbors configurations on NX-OS switches.
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - State 'absent' removes the whole BGP neighbor configuration
-    - default, where supported, restores params default value
+    - C(state=absent) removes the whole BGP neighbor configuration.
+    - Default, where supported, restores params default value.
 options:
     asn:
         description:
-            - BGP autonomous system number. Valid values are String,
+            - BGP autonomous system number. Valid values are string,
               Integer in ASPLAIN or ASDOT notation.
         required: true
     vrf:
@@ -180,16 +180,11 @@ options:
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 # create a new neighbor
@@ -210,7 +205,7 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"asn": "65535", "description": "just a description",
             "local_as": "20", "neighbor": "3.3.3.3",
@@ -218,11 +213,12 @@ proposed:
             "update_source": "Ethernet1/3", "vrf": "default"}
 existing:
     description: k/v pairs of existing BGP neighbor configuration
+    returned: verbose mode
     type: dict
     sample: {}
 end_state:
     description: k/v pairs of BGP neighbor configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"asn": "65535", "capability_negotiation": false,
             "connected_check": false, "description": "just a description",
@@ -250,12 +246,7 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
@@ -263,200 +254,17 @@ from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.network import NetworkModule
 from ansible.module_utils.shell import ShellError
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -468,14 +276,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -483,93 +283,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -621,303 +351,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -1045,7 +516,7 @@ def get_custom_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
     custom = [
         'log_neighbor_changes',
         'pwd',
@@ -1207,12 +678,13 @@ def main():
             m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
-                        required_together=[['pwd', 'pwd_type'],
-                                           ['timers_holdtime', 'timers_keepalive']],
+    module = get_network_module(argument_spec=argument_spec,
+                                required_together=[['timer_bgp_hold',
+                                            'timer_bgp_keepalive']],
                         supports_check_mode=True)
 
     state = module.params['state']
@@ -1281,7 +753,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py
index 5cd7413375..36db7ec8e2 100644
--- a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py
+++ b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py
@@ -24,17 +24,17 @@ DOCUMENTATION = '''
 ---
 module: nxos_bgp_neighbor_af
 version_added: "2.2"
-short_description: Manages BGP address-family's neighbors configuration
+short_description: Manages BGP address-family's neighbors configuration.
 description:
-    - Manages BGP address-family's neighbors configurations on NX-OS switches
+    - Manages BGP address-family's neighbors configurations on NX-OS switches.
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - State 'absent' removes the whole BGP address-family's
-      neighbor configuration
-    - default, when supported, removes properties
-    - to defaults maximum-prefix configuration, only
-      max_prefix_limit=default is needed
+    - C(state=absent) removes the whole BGP address-family's
+      neighbor configuration.
+    - Default, when supported, removes properties
+    - In order to default maximum-prefix configuration, only
+      C(max_prefix_limit=default) is needed.
 options:
     asn:
         description:
@@ -65,7 +65,7 @@ options:
     additional_paths_receive:
         description:
             - Valid values are enable for basic command enablement; disable
-              for disabling the command at the neighbor_af level
+              for disabling the command at the neighbor af level
               (it adds the disable keyword to the basic command); and inherit
               to remove the command at this level (the command value is
               inherited from a higher BGP layer).
@@ -75,7 +75,7 @@ options:
     additional_paths_send:
         description:
             - Valid values are enable for basic command enablement; disable
-              for disabling the command at the neighbor_af level
+              for disabling the command at the neighbor af level
               (it adds the disable keyword to the basic command); and inherit
               to remove the command at this level (the command value is
               inherited from a higher BGP layer).
@@ -129,7 +129,7 @@ options:
     default_originate_route_map:
         description:
             - Optional route-map for the default_originate property. Can be
-              used independently or in conjunction with default_originate.
+              used independently or in conjunction with C(default_originate).
               Valid values are a string defining a route-map name,
               or 'default'.
         required: false
@@ -248,21 +248,16 @@ options:
         default: null
     weight:
         description:
-            - weight value. Valid values are an integer value or 'default'.
+            - Weight value. Valid values are an integer value or 'default'.
         required: false
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 configure RR client
@@ -281,18 +276,19 @@ configure RR client
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"afi": "ipv4", "asn": "65535",
             "neighbor": "3.3.3.3", "route_reflector_client": true,
             "safi": "unicast", "vrf": "default"}
 existing:
     description: k/v pairs of existing configuration
+    returned: verbose mode
     type: dict
     sample: {}
 end_state:
     description: k/v pairs of configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"additional_paths_receive": "inherit",
             "additional_paths_send": "inherit",
@@ -327,12 +323,7 @@ changed:
 
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
@@ -340,200 +331,17 @@ from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.network import NetworkModule
 from ansible.module_utils.shell import ShellError
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -545,14 +353,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -560,93 +360,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -698,303 +428,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -1176,7 +647,7 @@ def get_custom_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
 
     custom = [
         'allowas_in_max',
@@ -1527,13 +998,13 @@ def main():
             suppress_inactive=dict(required=False, type='bool'),
             unsuppress_map=dict(required=False, type='str'),
             weight=dict(required=False, type='str'),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         mutually_exclusive=[['advertise_map_exist',
                                              'advertise_map_non_exist']],
                         supports_check_mode=True)
@@ -1635,7 +1106,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_evpn_global.py b/lib/ansible/modules/network/nxos/nxos_evpn_global.py
index 4a91165e9a..e2389ab526 100644
--- a/lib/ansible/modules/network/nxos/nxos_evpn_global.py
+++ b/lib/ansible/modules/network/nxos/nxos_evpn_global.py
@@ -35,12 +35,6 @@ options:
             - EVPN control plane.
         required: true
         choices: ['true', 'false']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 - nxos_evpn_global:
@@ -53,17 +47,17 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"nv_overlay_evpn": true}
 existing:
     description: k/v pairs of existing configuration
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"nv_overlay_evpn": false}
 end_state:
     description: k/v pairs of configuration after module execution
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"nv_overlay_evpn": true}
 updates:
@@ -80,213 +74,25 @@ changed:
 
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
-import itertools
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
 from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.network import NetworkModule
 from ansible.module_utils.shell import ShellError
 
-class ConfigLine(object):
 
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -298,14 +104,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -313,93 +111,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -451,18 +179,20 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
+def get_network_module(**kwargs):
+    try:
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-def get_config(module):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
+        try:
         config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
@@ -471,15 +201,22 @@ def load_config(module, candidate):
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -545,11 +282,11 @@ def get_commands(module, existing, proposed, candidate):
 def main():
     argument_spec = dict(
             nv_overlay_evpn=dict(required=True, type='bool'),
-            m_facts=dict(required=False, default=False, type='bool'),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     existing = invoke('get_existing', module)
@@ -571,7 +308,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module)
         result['end_state'] = end_state
         result['existing'] = existing
@@ -580,10 +317,5 @@ def main():
     module.exit_json(**result)
 
 
-from ansible.module_utils.basic import *
-from ansible.module_utils.urls import *
-from ansible.module_utils.shell import *
-from ansible.module_utils.netcfg import *
-from ansible.module_utils.nxos import *
 if __name__ == '__main__':
     main()
diff --git a/lib/ansible/modules/network/nxos/nxos_evpn_vni.py b/lib/ansible/modules/network/nxos/nxos_evpn_vni.py
index eaa4e628ec..15d620a6d1 100644
--- a/lib/ansible/modules/network/nxos/nxos_evpn_vni.py
+++ b/lib/ansible/modules/network/nxos/nxos_evpn_vni.py
@@ -24,7 +24,7 @@ DOCUMENTATION = '''
 ---
 module: nxos_evpn_vni
 version_added: "2.2"
-short_description: Manages Cisco EVPN VXLAN Network Identifier (VNI)
+short_description: Manages Cisco EVPN VXLAN Network Identifier (VNI).
 description:
     - Manages Cisco Ethernet Virtual Private Network (EVPN) VXLAN Network
       Identifier (VNI) configurations of a Nexus device.
@@ -34,14 +34,14 @@ notes:
     - default, where supported, restores params default value.
     - RD override is not permitted. You should set it to the default values
       first and then reconfigure it.
-    - route_target_both, route_target_import and route_target_export valid
-      values are a list of extended communities, (i.e. ['1.2.3.4:5', '33:55'])
-      or the keywords 'auto' or 'default'.
-    - The route_target_both property is discouraged due to the inconsistent
+    - C(route_target_both), C(route_target_import) and
+      C(route_target_export valid) values are a list of extended communities,
+      (i.e. ['1.2.3.4:5', '33:55']) or the keywords 'auto' or 'default'.
+    - The C(route_target_both) property is discouraged due to the inconsistent
       behavior of the property across Nexus platforms and image versions.
-      For this reason it is recommended to use explicit 'route_target_export'
-      and 'route_target_import' properties instead of route_target_both.
-    - RD valid values are a String in one of the route-distinguisher formats,
+      For this reason it is recommended to use explicit C(route_target_export)
+      and C(route_target_import) properties instead of C(route_target_both).
+    - RD valid values are a string in one of the route-distinguisher formats,
       the keyword 'auto', or the keyword 'default'.
 options:
     vni:
@@ -74,16 +74,11 @@ options:
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 - nxos_evpn_vni:
@@ -102,19 +97,20 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"route_target_import": ["5000:10", "4100:100",
              "5001:10"],"vni": "6000"}
 existing:
     description: k/v pairs of existing EVPN VNI configuration
+    returned: verbose mode
     type: dict
     sample: {"route_distinguisher": "70:10", "route_target_both": [],
             "route_target_export": [], "route_target_import": [
             "4100:100", "5000:10"], "vni": "6000"}
 end_state:
     description: k/v pairs of EVPN VNI configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"route_distinguisher": "70:10", "route_target_both": [],
              "route_target_export": [], "route_target_import": [
@@ -132,12 +128,7 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
@@ -145,200 +136,17 @@ from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.shell import ShellError
 from ansible.module_utils.network import NetworkModule
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -350,14 +158,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -365,93 +165,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -503,303 +233,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -847,7 +318,7 @@ def get_route_target_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
     parents = ['evpn', 'vni {0} l2'.format(module.params['vni'])]
     config = netcfg.get_section(parents)
 
@@ -943,13 +414,13 @@ def main():
             route_target_both=dict(required=False, type='list'),
             route_target_import=dict(required=False, type='list'),
             route_target_export=dict(required=False, type='list'),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     state = module.params['state']
@@ -996,7 +467,7 @@ def main():
 
                     candidate.add(remove_commands, parents=parents)
                     result = execute_config(module, candidate)
-                    time.sleep(20)
+                    time.sleep(30)
 
             candidate = CustomNetworkConfig(indent=3)
             candidate.add(commands, parents=parents)
@@ -1005,7 +476,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_feature.py b/lib/ansible/modules/network/nxos/nxos_feature.py
index f70d90b8eb..f959035172 100644
--- a/lib/ansible/modules/network/nxos/nxos_feature.py
+++ b/lib/ansible/modules/network/nxos/nxos_feature.py
@@ -24,9 +24,9 @@ DOCUMENTATION = '''
 ---
 module: nxos_feature
 version_added: "2.1"
-short_description: Manage features in NX-OS switches
+short_description: Manage features in NX-OS switches.
 description:
-    - Offers ability to enable and disable features in NX-OS
+    - Offers ability to enable and disable features in NX-OS.
 extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
@@ -81,11 +81,6 @@ end_state:
     returned: always
     type: dict
     sample: {"state": "disabled"}
-state:
-    description: state as sent in from the playbook
-    returned: always
-    type: string
-    sample: "disabled"
 updates:
     description: commands sent to the device
     returned: always
@@ -103,217 +98,32 @@ feature:
     sample: "vpc"
 '''
 
+import json
+import collections
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
-import json
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -325,14 +135,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -340,93 +142,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -478,303 +210,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -820,6 +293,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -970,9 +448,11 @@ def main():
             feature=dict(type='str', required=True),
             state=dict(choices=['enabled', 'disabled'], default='enabled',
                        required=False),
-            include_defaults=dict(default=False)
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     feature = validate_feature(module)
diff --git a/lib/ansible/modules/network/nxos/nxos_file_copy.py b/lib/ansible/modules/network/nxos/nxos_file_copy.py
index e4f9734c2e..08601b0fb4 100644
--- a/lib/ansible/modules/network/nxos/nxos_file_copy.py
+++ b/lib/ansible/modules/network/nxos/nxos_file_copy.py
@@ -26,14 +26,16 @@ module: nxos_file_copy
 version_added: "2.2"
 short_description: Copy a file to a remote NXOS device over SCP.
 description:
-    - Copy a file to the flash (or bootflash) remote network device on NXOS devices
+    - Copy a file to the flash (or bootflash) remote network device
+      on NXOS devices.
 author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
     - The feature must be enabled with feature scp-server.
-    - If the file is already present (md5 sums match), no transfer will take place.
+    - If the file is already present (md5 sums match), no transfer will
+      take place.
     - Check mode will tell you if the file would be copied.
 options:
     local_file:
@@ -49,7 +51,8 @@ options:
     file_system:
         description:
             - The remote file system of the device. If omitted,
-              devices that support a file_system parameter will use their default values.
+              devices that support a file_system parameter will use
+              their default values.
         required: false
         default: null
 '''
@@ -87,214 +90,28 @@ import paramiko
 import time
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -306,14 +123,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -321,93 +130,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -459,303 +198,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -764,6 +244,11 @@ def load_config(module, candidate):
 # END OF COMMON CODE
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -773,6 +258,19 @@ def execute_show(cmds, module, command_type=None):
         clie = get_exception()
         module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
+    except AttributeError:
+        try:
+            if command_type:
+                command_type = command_type_map.get(command_type)
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+            else:
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+        except ShellError:
+            clie = get_exception()
+            module.fail_json(msg='Error sending {0}'.format(cmds),
+                             error=str(clie))
     return response
 
 
@@ -850,7 +348,7 @@ def transfer_file(module, dest):
     scp = SCPClient(ssh.get_transport())
     try:
         scp.put(module.params['local_file'], full_remote_path)
-    except Exception as e:
+    except:
         time.sleep(10)
         temp_size = verify_remote_file_exists(
                     module, dest, file_system=module.params['file_system'])
@@ -870,8 +368,11 @@ def main():
             local_file=dict(required=True),
             remote_file=dict(required=False),
             file_system=dict(required=False, default='bootflash:'),
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     local_file = module.params['local_file']
diff --git a/lib/ansible/modules/network/nxos/nxos_hsrp.py b/lib/ansible/modules/network/nxos/nxos_hsrp.py
index e885a4605c..36d6f6a2f3 100644
--- a/lib/ansible/modules/network/nxos/nxos_hsrp.py
+++ b/lib/ansible/modules/network/nxos/nxos_hsrp.py
@@ -25,60 +25,60 @@ DOCUMENTATION = '''
 ---
 module: nxos_hsrp
 version_added: "2.2"
-short_description: Manages HSRP configuration on NX-OS switches
+short_description: Manages HSRP configuration on NX-OS switches.
 description:
-    - Manages HSRP configuration on NX-OS switches
+    - Manages HSRP configuration on NX-OS switches.
 extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
 notes:
-    - HSRP feature needs to be enabled first on the system
-    - SVIs must exist before using this module
-    - Interface must be a L3 port before using this module
-    - HSRP cannot be configured on loopback interfaces
+    - HSRP feature needs to be enabled first on the system.
+    - SVIs must exist before using this module.
+    - Interface must be a L3 port before using this module.
+    - HSRP cannot be configured on loopback interfaces.
     - MD5 authentication is only possible with HSRPv2 while it is ignored if
       HSRPv1 is used instead, while it will not raise any error. Here we allow
       MD5 authentication only with HSRPv2 in order to enforce better practice.
 options:
     group:
         description:
-            - HSRP group number
+            - HSRP group number.
         required: true
     interface:
         description:
-            - Full name of interface that is being managed for HSRP
+            - Full name of interface that is being managed for HSRP.
         required: true
     version:
         description:
-            - HSRP version
+            - HSRP version.
         required: false
         default: 2
         choices: ['1','2']
     priority:
         description:
-            - HSRP priority
+            - HSRP priority.
         required: false
         default: null
     vip:
         description:
-            - HSRP virtual IP address
+            - HSRP virtual IP address.
         required: false
         default: null
     auth_string:
         description:
-            - Authentication string
+            - Authentication string.
         required: false
         default: null
     auth_type:
         description:
-            - Authentication type
+            - Authentication type.
         required: false
         default: null
         choices: ['text','md5']
     state:
         description:
-            - Specify desired state of the resource
+            - Specify desired state of the resource.
         required: false
         choices: ['present','absent']
         default: 'present'
@@ -143,7 +143,6 @@ changed:
     sample: true
 '''
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 import json
 
 # COMMON CODE FOR MIGRATION
@@ -154,198 +153,17 @@ from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.shell import ShellError
 from ansible.module_utils.network import NetworkModule
 
-class ConfigLine(object):
 
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -357,14 +175,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -372,93 +182,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -510,303 +250,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -856,6 +337,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -863,7 +349,7 @@ def execute_show(cmds, module, command_type=None):
             response = module.execute(cmds)
     except ShellError:
         clie = get_exception()
-        module.fail_json(msg='Error sending {0}'.format(command),
+        module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
     except AttributeError:
         try:
@@ -1129,8 +615,11 @@ def main():
             auth_string=dict(type='str', required=False),
             state=dict(choices=['absent', 'present'], required=False,
                        default='present'),
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     interface = module.params['interface'].lower()
diff --git a/lib/ansible/modules/network/nxos/nxos_igmp.py b/lib/ansible/modules/network/nxos/nxos_igmp.py
index cc15fbca55..216922f226 100644
--- a/lib/ansible/modules/network/nxos/nxos_igmp.py
+++ b/lib/ansible/modules/network/nxos/nxos_igmp.py
@@ -24,17 +24,18 @@ DOCUMENTATION = '''
 ---
 module: nxos_igmp
 version_added: "2.2"
-short_description: Manages IGMP global configuration
+short_description: Manages IGMP global configuration.
 description:
-    - Manages IGMP global configuration configuration settings
+    - Manages IGMP global configuration configuration settings.
 extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
 notes:
-    - When state=default, all supported params will be reset to a default state
+    - When C(state=default), all supported params will be reset to a
+      default state.
     - If restart is set to true with other params set, the restart will happen
-      last, i.e. after the configuration takes place
+      last, i.e. after the configuration takes place.
 options:
     flush_routes:
         description:
@@ -46,19 +47,19 @@ options:
     enforce_rtr_alert:
         description:
             - Enables or disables the enforce router alert option check for
-              IGMPv2 and IGMPv3 packets
+              IGMPv2 and IGMPv3 packets.
         required: false
         default: null
         choices: ['true', 'false']
     restart:
         description:
-            - restarts the igmp process (using an exec config command)
+            - Restarts the igmp process (using an exec config command).
         required: false
         default: null
         choices: ['true', 'false']
     state:
         description:
-            - Manages desired state of the resource
+            - Manages desired state of the resource.
         required: false
         default: present
         choices: ['present', 'default']
@@ -84,17 +85,17 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: when C(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"enforce_rtr_alert": true, "flush_routes": true}
 existing:
     description: k/v pairs of existing IGMP configuration
-    returned: when C(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"enforce_rtr_alert": true, "flush_routes": false}
 end_state:
     description: k/v pairs of IGMP configuration after module execution
-    returned: when C(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"enforce_rtr_alert": true, "flush_routes": true}
 updates:
@@ -110,215 +111,28 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
-import json
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -330,14 +144,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -345,93 +151,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -483,303 +219,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -806,7 +283,7 @@ def get_value(arg, config):
 
 def get_existing(module, args):
     existing = {}
-    config = str(custom_get_config(module))
+    config = str(get_config(module))
 
     for arg in args:
         existing[arg] = get_value(arg, config)
@@ -862,11 +339,11 @@ def main():
             enforce_rtr_alert=dict(type='bool'),
             restart=dict(type='bool', default=False),
             state=dict(choices=['present', 'default'], default='present'),
-            m_facts=dict(required=False, default=False, type='bool'),
-            include_defaults=dict(default=False)
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     state = module.params['state']
@@ -909,7 +386,7 @@ def main():
     if restart:
         proposed['restart'] = restart
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_igmp_interface.py b/lib/ansible/modules/network/nxos/nxos_igmp_interface.py
index 586a6fed53..7294455a48 100644
--- a/lib/ansible/modules/network/nxos/nxos_igmp_interface.py
+++ b/lib/ansible/modules/network/nxos/nxos_igmp_interface.py
@@ -24,35 +24,32 @@ DOCUMENTATION = '''
 ---
 module: nxos_igmp_interface
 version_added: "2.2"
-short_description: Manages IGMP interface configuration
+short_description: Manages IGMP interface configuration.
 description:
-    - Manages IGMP interface configuration settings
+    - Manages IGMP interface configuration settings.
 extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
 notes:
-    - When state=default, supported params will be reset to a default state.
-      These include: version, startup_query_interval, startup_query_count,
-      robustness, querier_timeout, query_mrt, query_interval, last_member_qrt,
-      last_member_query_count, group_timeout, report_llg, and immediate_leave
-    - When state=absent, all configs for oif_prefix, oif_source, and
-      oif_routemap will be removed.
-    - PIM must be enabled to use this module
-    - This module is for Layer 3 interfaces
+    - When C(state=default), supported params will be reset to a default state.
+      These include C(version), C(startup_query_interval),
+      C(startup_query_count), C(robustness), C(querier_timeout), C(query_mrt),
+      C(query_interval), C(last_member_qrt), C(last_member_query_count),
+      C(group_timeout), C(report_llg), and C(immediate_leave).
+    - When C(state=absent), all configs for C(oif_prefix), C(oif_source), and
+      C(oif_routemap) will be removed.
+    - PIM must be enabled to use this module.
+    - This module is for Layer 3 interfaces.
     - Route-map check not performed (same as CLI) check when configuring
       route-map with 'static-oif'
     - If restart is set to true with other params set, the restart will happen
-      last, i.e. after the configuration takes place
-    - While username and password are not required params, they are
-      if you are not using the .netauth file.  .netauth file is recommended
-      as it will clean up the each task in the playbook by not requiring
-      the username and password params for every tasks.
-    - Using the username and password params will override the .netauth file
+      last, i.e. after the configuration takes place.
 options:
     interface:
         description:
-            - The FULL interface name for IGMP configuration.
+            - The full interface name for IGMP configuration.
+              e.g. I(Ethernet1/2).
         required: true
     version:
         description:
@@ -102,7 +99,7 @@ options:
         description:
             - Sets the query interval waited after sending membership reports
               before the software deletes the group state. Values can range
-              from 1 to 25 seconds. The default is 1 second
+              from 1 to 25 seconds. The default is 1 second.
         required: false
         default: null
     last_member_query_count:
@@ -156,13 +153,13 @@ options:
         default: null
     restart:
         description:
-            - Restart IGMP
+            - Restart IGMP.
         required: false
         choices: ['true', 'false']
         default: null
     state:
         description:
-            - Manages desired state of the resource
+            - Manages desired state of the resource.
         required: false
         default: present
         choices: ['present', 'default']
@@ -236,217 +233,32 @@ changed:
     sample: true
 '''
 
+import json
+import collections
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
-import json
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -458,14 +270,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -473,93 +277,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -611,303 +345,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -915,7 +390,6 @@ def load_config(module, candidate):
     return result
 # END OF COMMON CODE
 
-
 def get_cli_body_ssh(command, response, module):
     """Get response for when transport=cli.  This is kind of a hack and mainly
     needed because these modules were originally written for NX-API.  And
@@ -939,6 +413,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -946,7 +425,7 @@ def execute_show(cmds, module, command_type=None):
             response = module.execute(cmds)
     except ShellError:
         clie = get_exception()
-        module.fail_json(msg='Error sending {0}'.format(command),
+        module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
     except AttributeError:
         try:
@@ -1272,10 +751,11 @@ def main():
             restart=dict(type='bool', default=False),
             state=dict(choices=['present', 'absent', 'default'],
                        default='present'),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     state = module.params['state']
diff --git a/lib/ansible/modules/network/nxos/nxos_interface_ospf.py b/lib/ansible/modules/network/nxos/nxos_interface_ospf.py
index c04b2eeafb..c4a2ee6be4 100644
--- a/lib/ansible/modules/network/nxos/nxos_interface_ospf.py
+++ b/lib/ansible/modules/network/nxos/nxos_interface_ospf.py
@@ -30,11 +30,11 @@ description:
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - default, where supported, restores params default value
+    - Default, where supported, restores params default value.
     - To remove an existing authentication configuration you should use
-      message_digest_key_id=default plus all other options matching their
+      C(message_digest_key_id=default) plus all other options matching their
       existing values.
-    - State absent remove the whole OSPF interface configuration
+    - C(state=absent) removes the whole OSPF interface configuration.
 options:
     interface:
         description:
@@ -84,7 +84,7 @@ options:
         default: null
     message_digest_key_id:
         description:
-            - md5 authentication key-id associated with the ospf instance.
+            - Md5 authentication key-id associated with the ospf instance.
               If this is present, message_digest_encryption_type,
               message_digest_algorithm_type and message_digest_password are
               mandatory. Valid value is an integer and 'default'.
@@ -111,16 +111,11 @@ options:
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 - nxos_interface_ospf:
@@ -136,11 +131,12 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"area": "1", "interface": "ethernet1/32", "ospf": "1"}
 existing:
     description: k/v pairs of existing OSPF configuration
+    returned: verbose mode
     type: dict
     sample: {"area": "", "cost": "", "dead_interval": "",
             "hello_interval": "", "interface": "ethernet1/32",
@@ -150,7 +146,7 @@ existing:
             "ospf": "", "passive_interface": false}
 end_state:
     description: k/v pairs of OSPF configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"area": "0.0.0.1", "cost": "", "dead_interval": "",
             "hello_interval": "", "interface": "ethernet1/32",
@@ -172,14 +168,8 @@ changed:
 
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
 from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
@@ -187,198 +177,16 @@ from ansible.module_utils.network import NetworkModule
 from ansible.module_utils.shell import ShellError
 
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -390,14 +198,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -405,93 +205,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -543,303 +273,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -954,7 +425,7 @@ def get_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
     parents = ['interface {0}'.format(module.params['interface'].capitalize())]
     config = netcfg.get_section(parents)
     if 'ospf' in config:
@@ -1123,13 +594,13 @@ def main():
             message_digest_encryption_type=dict(required=False, type='str',
                                                 choices=['cisco_type_7','3des']),
             message_digest_password=dict(required=False, type='str'),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         required_together=[['message_digest_key_id',
                                             'message_digest_algorithm_type',
                                             'message_digest_encryption_type',
@@ -1197,7 +668,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_ip_interface.py b/lib/ansible/modules/network/nxos/nxos_ip_interface.py
index 29b6326eb4..09fd478044 100644
--- a/lib/ansible/modules/network/nxos/nxos_ip_interface.py
+++ b/lib/ansible/modules/network/nxos/nxos_ip_interface.py
@@ -24,37 +24,37 @@ DOCUMENTATION = '''
 ---
 module: nxos_ip_interface
 version_added: "2.1"
-short_description: Manages L3 attributes for IPv4 and IPv6 interfaces
+short_description: Manages L3 attributes for IPv4 and IPv6 interfaces.
 description:
-    - Manages Layer 3 attributes for IPv4 and IPv6 interfaces
+    - Manages Layer 3 attributes for IPv4 and IPv6 interfaces.
 extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
 notes:
-    - Interface must already be a L3 port when using this module
-    - Logical interfaces (po, loop, svi) must be created first
-    - I(mask) must be inserted in decimal format (i.e. 24) for
+    - Interface must already be a L3 port when using this module.
+    - Logical interfaces (po, loop, svi) must be created first.
+    - C(mask) must be inserted in decimal format (i.e. 24) for
       both IPv6 and IPv4.
     - A single interface can have multiple IPv6 configured.
 options:
     interface:
         description:
-            - Full name of interface, i.e. Ethernet1/1, vlan10
+            - Full name of interface, i.e. Ethernet1/1, vlan10.
         required: true
     addr:
         description:
-            - IPv4 or IPv6 Address
+            - IPv4 or IPv6 Address.
         required: false
         default: null
     mask:
         description:
-            - Subnet mask for IPv4 or IPv6 Address in decimal format
+            - Subnet mask for IPv4 or IPv6 Address in decimal format.
         required: false
         default: null
     state:
         description:
-            - Specify desired state of the resource
+            - Specify desired state of the resource.
         required: false
         default: present
         choices: ['present','absent']
@@ -99,11 +99,6 @@ end_state:
     sample: {"addresses": [{"addr": "20.20.20.20", "mask": 24}],
             "interface": "ethernet1/32", "prefix": "20.20.20.0",
             "type": "ethernet", "vrf": "default"}
-state:
-    description: state as sent in from the playbook
-    returned: always
-    type: string
-    sample: "present"
 updates:
     description: commands sent to the device
     returned: always
@@ -116,216 +111,32 @@ changed:
     sample: true
 '''
 
-# COMMON CODE FOR MIGRATION
-
-import re
-import time
-import collections
-import itertools
-import shlex
 import json
+import collections
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -337,14 +148,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -352,93 +155,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -490,303 +223,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -834,6 +308,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -1157,9 +636,11 @@ def main():
             mask=dict(type='str', required=False),
             state=dict(required=False, default='present',
                        choices=['present', 'absent']),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     addr = module.params['addr']
diff --git a/lib/ansible/modules/network/nxos/nxos_ntp_options.py b/lib/ansible/modules/network/nxos/nxos_ntp_options.py
index 9d4f02d203..010e67c886 100644
--- a/lib/ansible/modules/network/nxos/nxos_ntp_options.py
+++ b/lib/ansible/modules/network/nxos/nxos_ntp_options.py
@@ -24,6 +24,7 @@ DOCUMENTATION = '''
 ---
 
 module: nxos_ntp_options
+version_added: "2.2"
 short_description: Manages NTP options.
 description:
     - Manages NTP options, e.g. authoritative server and logging.
diff --git a/lib/ansible/modules/network/nxos/nxos_ospf.py b/lib/ansible/modules/network/nxos/nxos_ospf.py
index 0aa1620b5a..d6f47bbc35 100644
--- a/lib/ansible/modules/network/nxos/nxos_ospf.py
+++ b/lib/ansible/modules/network/nxos/nxos_ospf.py
@@ -36,16 +36,11 @@ options:
         required: true
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 
 EXAMPLES = '''
@@ -60,22 +55,22 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"ospf": "1"}
 existing:
     description: k/v pairs of existing configuration
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"ospf": ["2"]}
 end_state:
     description: k/v pairs of configuration after module execution
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"ospf": ["1", "2"]}
 updates:
     description: commands sent to the device
-    returned: when I(m_facts)=true
+    returned: always
     type: list
     sample: ["router ospf 1"]
 changed:
@@ -87,213 +82,25 @@ changed:
 
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
-import itertools
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
 from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.network import NetworkModule
 from ansible.module_utils.shell import ShellError
 
-class ConfigLine(object):
 
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -305,14 +112,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -320,93 +119,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -458,18 +187,20 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
+def get_network_module(**kwargs):
+    try:
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-def get_config(module):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
+        try:
         config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
@@ -478,15 +209,22 @@ def load_config(module, candidate):
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -560,13 +298,13 @@ def state_absent(module, proposed, candidate):
 def main():
     argument_spec = dict(
             ospf=dict(required=True, type='str'),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     state = module.params['state']
@@ -596,7 +334,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module)
         result['end_state'] = end_state
         result['existing'] = existing
@@ -605,11 +343,5 @@ def main():
     module.exit_json(**result)
 
 
-
-from ansible.module_utils.basic import *
-from ansible.module_utils.urls import *
-from ansible.module_utils.shell import *
-from ansible.module_utils.netcfg import *
-from ansible.module_utils.nxos import *
 if __name__ == '__main__':
     main()
diff --git a/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py b/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py
index 0071504b89..3d049edcad 100644
--- a/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py
+++ b/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py
@@ -111,12 +111,6 @@ options:
               Valid values are an integer, in Mbps, or the keyword 'default'.
         required: false
         default: null
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 
 EXAMPLES = '''
@@ -129,7 +123,6 @@ EXAMPLES = '''
     timer_throttle_lsa_hold: 1100
     timer_throttle_lsa_max: 3000
     vrf: test
-    m_facts: true
     state: present
     username: "{{ un }}"
     password: "{{ pwd }}"
@@ -139,7 +132,7 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"ospf": "1", "timer_throttle_lsa_hold": "1100",
             "timer_throttle_lsa_max": "3000", "timer_throttle_lsa_start": "60",
@@ -148,7 +141,7 @@ proposed:
             "vrf": "test"}
 existing:
     description: k/v pairs of existing configuration
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"auto_cost": "40000", "default_metric": "", "log_adjacency": "",
             "ospf": "1", "router_id": "", "timer_throttle_lsa_hold": "5000",
@@ -158,7 +151,7 @@ existing:
             "timer_throttle_spf_start": "200", "vrf": "test"}
 end_state:
     description: k/v pairs of configuration after module execution
-    returned: when I(m_facts)=true
+    returned: verbose mode
     type: dict
     sample: {"auto_cost": "40000", "default_metric": "", "log_adjacency": "",
             "ospf": "1", "router_id": "", "timer_throttle_lsa_hold": "1100",
@@ -180,12 +173,7 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
@@ -193,200 +181,17 @@ from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.network import NetworkModule
 from ansible.module_utils.shell import ShellError
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -398,14 +203,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -413,93 +210,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -551,303 +278,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -855,6 +323,7 @@ def load_config(module, candidate):
     return result
 # END OF COMMON CODE
 
+
 PARAM_TO_COMMAND_KEYMAP = {
     'router_id': 'router-id',
     'default_metric': 'default-metric',
@@ -912,7 +381,7 @@ def get_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
     parents = ['router ospf {0}'.format(module.params['ospf'])]
 
     if module.params['vrf'] != 'default':
@@ -1052,13 +521,13 @@ def main():
             timer_throttle_spf_hold=dict(required=False, type='str'),
             timer_throttle_spf_max=dict(required=False, type='str'),
             auto_cost=dict(required=False, type='str'),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     state = module.params['state']
@@ -1111,7 +580,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_overlay_global.py b/lib/ansible/modules/network/nxos/nxos_overlay_global.py
index 3864eb0a93..dda0d48413 100644
--- a/lib/ansible/modules/network/nxos/nxos_overlay_global.py
+++ b/lib/ansible/modules/network/nxos/nxos_overlay_global.py
@@ -30,7 +30,7 @@ description:
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - default, where supported, restores params default value
+    - Default restores params default value
     - Supported MAC address format are "E.E.E", "EE-EE-EE-EE-EE-EE",
       "EE:EE:EE:EE:EE:EE" and "EEEE.EEEE.EEEE"
 options:
@@ -39,13 +39,8 @@ options:
             - Anycast gateway mac of the switch.
         required: true
         default: null
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
+
 EXAMPLES = '''
 - nxos_overlay_global:
     anycast_gateway_mac: "b.b.b"
@@ -57,23 +52,56 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
-    sample: {"12:34:56:78:9a:bc"}
+    sample: {"asn": "65535", "router_id": "1.1.1.1", "vrf": "test"}
 existing:
-    description: k/v pairs of existing configuration
+    description: k/v pairs of existing BGP configuration
+    returned: verbose mode
     type: dict
-    sample: {"anycast_gateway_mac": "000E.000E.000E"}
+    sample: {"asn": "65535", "bestpath_always_compare_med": false,
+            "bestpath_aspath_multipath_relax": false,
+            "bestpath_compare_neighborid": false,
+            "bestpath_compare_routerid": false,
+            "bestpath_cost_community_ignore": false,
+            "bestpath_med_confed": false,
+            "bestpath_med_missing_as_worst": false,
+            "bestpath_med_non_deterministic": false, "cluster_id": "",
+            "confederation_id": "", "confederation_peers": "",
+            "graceful_restart": true, "graceful_restart_helper": false,
+            "graceful_restart_timers_restart": "120",
+            "graceful_restart_timers_stalepath_time": "300", "local_as": "",
+            "log_neighbor_changes": false, "maxas_limit": "",
+            "neighbor_down_fib_accelerate": false, "reconnect_interval": "60",
+            "router_id": "11.11.11.11", "suppress_fib_pending": false,
+            "timer_bestpath_limit": "", "timer_bgp_hold": "180",
+            "timer_bgp_keepalive": "60", "vrf": "test"}
 end_state:
-    description: k/v pairs of configuration after module execution
-    returned: always
+    description: k/v pairs of BGP configuration after module execution
+    returned: verbose mode
     type: dict
-    sample: {"anycast_gateway_mac": "1234.5678.9ABC"}
+    sample: {"asn": "65535", "bestpath_always_compare_med": false,
+            "bestpath_aspath_multipath_relax": false,
+            "bestpath_compare_neighborid": false,
+            "bestpath_compare_routerid": false,
+            "bestpath_cost_community_ignore": false,
+            "bestpath_med_confed": false,
+            "bestpath_med_missing_as_worst": false,
+            "bestpath_med_non_deterministic": false, "cluster_id": "",
+            "confederation_id": "", "confederation_peers": "",
+            "graceful_restart": true, "graceful_restart_helper": false,
+            "graceful_restart_timers_restart": "120",
+            "graceful_restart_timers_stalepath_time": "300", "local_as": "",
+            "log_neighbor_changes": false, "maxas_limit": "",
+            "neighbor_down_fib_accelerate": false, "reconnect_interval": "60",
+            "router_id": "1.1.1.1",  "suppress_fib_pending": false,
+            "timer_bestpath_limit": "", "timer_bgp_hold": "180",
+            "timer_bgp_keepalive": "60", "vrf": "test"}
 updates:
     description: commands sent to the device
     returned: always
     type: list
-    sample: ["fabric forwarding anycast-gateway-mac 1234.5678.9ABC"]
+    sample: ["router bgp 65535", "vrf test", "router-id 1.1.1.1"]
 changed:
     description: check to see if a change was made on the device
     returned: always
@@ -82,214 +110,28 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -301,14 +143,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -316,93 +150,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -454,303 +218,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -779,7 +284,7 @@ def get_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    config = str(custom_get_config(module))
+    config = str(get_config(module))
 
     for arg in args:
         existing[arg] = get_value(arg, config, module)
@@ -867,10 +372,11 @@ def main():
     argument_spec = dict(
             anycast_gateway_mac=dict(required=True, type='str'),
             m_facts=dict(required=False, default=False, type='bool'),
-            include_defaults=dict(default=True)
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     args =  [
@@ -894,7 +400,7 @@ def main():
         module.fail_json(msg=str(exc))
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_pim.py b/lib/ansible/modules/network/nxos/nxos_pim.py
index 2ee67ae954..7fc4080def 100644
--- a/lib/ansible/modules/network/nxos/nxos_pim.py
+++ b/lib/ansible/modules/network/nxos/nxos_pim.py
@@ -24,9 +24,9 @@ DOCUMENTATION = '''
 ---
 module: nxos_pim
 version_added: "2.2"
-short_description: Manages configuration of an Protocol Independent Multicast (PIM) instance.
+short_description: Manages configuration of a PIM instance.
 description:
-    - Manages configuration of an Protocol Independent Multicast (PIM) instance.
+    - Manages configuration of a Protocol Independent Multicast (PIM) instance.
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 options:
@@ -35,12 +35,6 @@ options:
             - Configure group ranges for Source Specific Multicast (SSM).
               Valid values are multicast addresses or the keyword 'none'.
         required: true
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 - nxos_pim:
@@ -53,16 +47,17 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"ssm_range": "232.0.0.0/8"}
 existing:
     description: k/v pairs of existing PIM configuration
+    returned: verbose mode
     type: dict
     sample: {"ssm_range": none}
 end_state:
     description: k/v pairs of BGP configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"ssm_range": "232.0.0.0/8"}
 updates:
@@ -79,214 +74,28 @@ changed:
 
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -298,14 +107,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -313,93 +114,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -451,303 +182,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -779,7 +251,7 @@ def get_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    config = str(custom_get_config(module))
+    config = str(get_config(module))
     for arg in args:
         existing[arg] = get_value(arg, config, module)
     return existing
@@ -815,10 +287,11 @@ def main():
     argument_spec = dict(
             ssm_range=dict(required=True, type='str'),
             m_facts=dict(required=False, default=False, type='bool'),
-            include_defaults=dict(default=False)
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     splitted_ssm_range = module.params['ssm_range'].split('.')
@@ -847,7 +320,7 @@ def main():
         module.fail_json(msg=str(exc))
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py b/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py
index 2b1fc484d2..5149d4d3fb 100644
--- a/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py
+++ b/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py
@@ -24,15 +24,14 @@ DOCUMENTATION = '''
 ---
 module: nxos_pim_rp_address
 version_added: "2.2"
-short_description: Manages configuration of an Protocol Independent Multicast
-                   (PIM) static rendezvous point (RP) address instance.
+short_description: Manages configuration of an PIM static RP address instance.
 description:
     - Manages configuration of an Protocol Independent Multicast (PIM) static
       rendezvous point (RP) address instance.
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - state=absent remove the whole rp-address configuration, if existing.
+    - C(state=absent) remove the whole rp-address configuration, if existing.
 options:
     rp_address:
         description:
@@ -63,12 +62,6 @@ options:
         required: false
         choices: ['true','false']
         default: null
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 - nxos_pim_rp_address:
@@ -82,16 +75,17 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"rp_address": "10.1.1.21"}
 existing:
     description: list of existing pim rp-address configuration entries
+    returned: verbose mode
     type: list
     sample: []
 end_state:
     description: pim rp-address configuration entries after module execution
-    returned: always
+    returned: verbose mode
     type: list
     sample: [{"bidir": false, "group_list": "224.0.0.0/4",
             "rp_address": "10.1.1.21"}]
@@ -110,214 +104,28 @@ changed:
 
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -329,14 +137,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -344,93 +144,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -482,303 +212,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -825,7 +296,7 @@ def get_value(config, module):
 
 def get_existing(module, args):
     existing = {}
-    config = str(custom_get_config(module))
+    config = str(get_config(module))
     existing = get_value(config, module)
     return existing
 
@@ -880,13 +351,13 @@ def main():
             prefix_list=dict(required=False, type='str'),
             route_map=dict(required=False, type='str'),
             bidir=dict(required=False, type='bool'),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=False)
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         mutually_exclusive=[['group_list', 'route_map'],
                                             ['group_list', 'prefix_list'],
                                             ['route_map', 'prefix_list']],
@@ -929,7 +400,7 @@ def main():
         module.fail_json(msg=str(exc))
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_ping.py b/lib/ansible/modules/network/nxos/nxos_ping.py
index b29c30910d..1bb7b044d7 100644
--- a/lib/ansible/modules/network/nxos/nxos_ping.py
+++ b/lib/ansible/modules/network/nxos/nxos_ping.py
@@ -24,29 +24,31 @@ DOCUMENTATION = '''
 ---
 module: nxos_ping
 version_added: "2.1"
-short_description: Tests reachability using ping from Nexus switch
+short_description: Tests reachability using ping from Nexus switch.
 description:
-    - Tests reachability using ping from switch to a remote destination
+    - Tests reachability using ping from switch to a remote destination.
 extends_documentation_fragment: nxos
-author: Jason Edelman (@jedelman8), Gabriele Gerbino (@GGabriele)
+author:
+    - Jason Edelman (@jedelman8)
+    - Gabriele Gerbino (@GGabriele)
 options:
     dest:
         description:
-            - IP address or hostname (resolvable by switch) of remote node
+            - IP address or hostname (resolvable by switch) of remote node.
         required: true
     count:
         description:
-            - Number of packets to send
+            - Number of packets to send.
         required: false
         default: 2
     source:
         description:
-            - Source IP Address
+            - Source IP Address.
         required: false
         default: null
     vrf:
         description:
-            - Outgoing VRF
+            - Outgoing VRF.
         required: false
         default: null
 '''
@@ -114,216 +116,32 @@ packet_loss:
     sample: "0.00%"
 '''
 
-# COMMON CODE FOR MIGRATION
-
-import re
-import time
-import collections
-import itertools
-import shlex
 import json
+import collections
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -335,14 +153,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -350,93 +160,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -488,303 +228,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -833,6 +314,11 @@ def get_statistics_summary_line(response_as_list):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -842,6 +328,19 @@ def execute_show(cmds, module, command_type=None):
         clie = get_exception()
         module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
+    except AttributeError:
+        try:
+            if command_type:
+                command_type = command_type_map.get(command_type)
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+            else:
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+        except ShellError:
+            clie = get_exception()
+            module.fail_json(msg='Error sending {0}'.format(cmds),
+                             error=str(clie))
     return response
 
 
@@ -885,8 +384,11 @@ def main():
             source=dict(required=False),
             state=dict(required=False, choices=['present', 'absent'],
                        default='present'),
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     destination = module.params['dest']
diff --git a/lib/ansible/modules/network/nxos/nxos_reboot.py b/lib/ansible/modules/network/nxos/nxos_reboot.py
index 78d5810074..ce31a9b8f9 100644
--- a/lib/ansible/modules/network/nxos/nxos_reboot.py
+++ b/lib/ansible/modules/network/nxos/nxos_reboot.py
@@ -26,7 +26,7 @@ module: nxos_reboot
 version_added: 2.2
 short_description: Reboot a network device.
 description:
-    - Reboot a network device
+    - Reboot a network device.
 extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
@@ -58,215 +58,32 @@ rebooted:
     sample: true
 '''
 
-# COMMON CODE FOR MIGRATION
-
-import re
-import time
+import json
 import collections
-import itertools
-import shlex
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -278,14 +95,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -293,93 +102,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -431,303 +170,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -743,6 +223,11 @@ def reboot(module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -752,12 +237,25 @@ def execute_show(cmds, module, command_type=None):
         clie = get_exception()
         module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
+    except AttributeError:
+        try:
+            if command_type:
+                command_type = command_type_map.get(command_type)
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+            else:
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+        except ShellError:
+            clie = get_exception()
+            module.fail_json(msg='Error sending {0}'.format(cmds),
+                             error=str(clie))
     return response
 
 
 def execute_show_command(command, module, command_type='cli_show'):
     if module.params['transport'] == 'cli':
-        body = execute_show(command, module, reboot=reboot)
+        body = execute_show(command, module)
     elif module.params['transport'] == 'nxapi':
         body = execute_show(command, module, command_type=command_type)
 
@@ -765,16 +263,18 @@ def execute_show_command(command, module, command_type='cli_show'):
 
 
 def disable_confirmation(module):
-    command = 'terminal dont-ask'
+    command = ['terminal dont-ask']
     body = execute_show_command(command, module, command_type='cli_show_ascii')[0]
 
 
 def main():
     argument_spec = dict(
             confirm=dict(required=True, type='bool'),
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     confirm = module.params['confirm']
diff --git a/lib/ansible/modules/network/nxos/nxos_rollback.py b/lib/ansible/modules/network/nxos/nxos_rollback.py
index 731e096146..bff47e5512 100644
--- a/lib/ansible/modules/network/nxos/nxos_rollback.py
+++ b/lib/ansible/modules/network/nxos/nxos_rollback.py
@@ -23,24 +23,29 @@ ANSIBLE_METADATA = {'status': ['preview'],
 DOCUMENTATION = '''
 ---
 module: nxos_rollback
-short_description: Set a checkpoint or rollback to a checkpoint
+version_added: "2.2"
+short_description: Set a checkpoint or rollback to a checkpoint.
 description:
-    - This module offers the ability to set a configuration checkpoint file or rollback
-      to a configuration checkpoint file on Cisco NXOS switches-
+    - This module offers the ability to set a configuration checkpoint
+      file or rollback to a configuration checkpoint file on Cisco NXOS
+      switches.
+extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
 notes:
-    - Sometimes C(transport)=nxapi may cause a timeout error.
+    - Sometimes C(transport=nxapi) may cause a timeout error.
 options:
     checkpoint_file:
         description:
-            - Name of checkpoint file to create. Mutually exclusive with rollback_to.
+            - Name of checkpoint file to create. Mutually exclusive
+              with rollback_to.
         required: false
         default: null
     rollback_to:
         description:
-            - Name of checkpoint file to rollback to. Mutually exclusive with checkpoint_file.
+            - Name of checkpoint file to rollback to. Mutually exclusive
+              with checkpoint_file.
         required: false
         default: null
 '''
@@ -73,214 +78,28 @@ status:
 
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -292,14 +111,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -307,93 +118,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -445,303 +186,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST', timeout=20)
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -751,15 +233,34 @@ def load_config(module, candidate):
 
 
 def execute_commands(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
-            module.execute(cmds, command_type=command_type)
+            response = module.execute(cmds, command_type=command_type)
         else:
-            module.execute(cmds)
+            response = module.execute(cmds)
     except ShellError:
         clie = get_exception()
         module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
+    except AttributeError:
+    try:
+        if command_type:
+                command_type = command_type_map.get(command_type)
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+        else:
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+    except ShellError:
+        clie = get_exception()
+        module.fail_json(msg='Error sending {0}'.format(cmds),
+                         error=str(clie))
+    return response
 
 
 def prepare_show_command(command, module):
@@ -776,16 +277,27 @@ def checkpoint(filename, module):
 
 def rollback(filename, module):
     commands = ['rollback running-config file %s' % filename]
+    try:
     module.configure(commands)
+    except AttributeError:
+        try:
+            module.cli.add_commands(commands, output='config')
+            module.cli.run_commands()
+        except ShellError:
+            clie = get_exception()
+            module.fail_json(msg='Error sending CLI commands',
+                             error=str(clie), commands=commands)
 
 
 def main():
     argument_spec = dict(
             checkpoint_file=dict(required=False),
             rollback_to=dict(required=False),
+            include_defaults=dict(default=True),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         mutually_exclusive=[['checkpoint_file',
                                              'rollback_to']],
                         supports_check_mode=False)
diff --git a/lib/ansible/modules/network/nxos/nxos_smu.py b/lib/ansible/modules/network/nxos/nxos_smu.py
index 4698bf6452..d487aaf64b 100644
--- a/lib/ansible/modules/network/nxos/nxos_smu.py
+++ b/lib/ansible/modules/network/nxos/nxos_smu.py
@@ -32,11 +32,11 @@ author: Gabriele Gerbino (@GGabriele)
 notes:
     - The module can only activate and commit a package,
       not remove or deactivate it.
-    - Use I(transport)=nxapi to avoid connection timeout
+    - Use C(transport=nxapi) to avoid connection timeout
 options:
     pkg:
         description:
-            - Name of the remote package
+            - Name of the remote package.
         required: true
     file_system:
         description:
@@ -81,215 +81,32 @@ changed:
 '''
 
 import time
-# COMMON CODE FOR MIGRATION
-
-import re
-import time
+import json
 import collections
-import itertools
-import shlex
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -301,14 +118,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -316,93 +125,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -454,303 +193,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -759,6 +239,11 @@ def load_config(module, candidate):
 # END OF COMMON CODE
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -861,8 +346,11 @@ def main():
     argument_spec = dict(
             pkg=dict(required=True),
             file_system=dict(required=False, default='bootflash:'),
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     pkg = module.params['pkg']
diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_host.py b/lib/ansible/modules/network/nxos/nxos_snmp_host.py
index 99ef9944f1..366da22a91 100644
--- a/lib/ansible/modules/network/nxos/nxos_snmp_host.py
+++ b/lib/ansible/modules/network/nxos/nxos_snmp_host.py
@@ -1,18 +1,21 @@
-#!/usr/bin/env python
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+#
 
-# Copyright 2015 Jason Edelman <jedelman8@gmail.com>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
 
 ANSIBLE_METADATA = {'status': ['preview'],
                     'supported_by': 'community',
@@ -26,7 +29,9 @@ short_description: Manages SNMP host configuration.
 description:
     - Manages SNMP host configuration parameters.
 extends_documentation_fragment: nxos
-author: Jason Edelman (@jedelman8)
+author:
+    - Jason Edelman (@jedelman8)
+    - Gabriele Gerbino (@GGabriele)
 notes:
     - C(state=absent) removes the host configuration if it is configured.
 options:
diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_location.py b/lib/ansible/modules/network/nxos/nxos_snmp_location.py
index e5939bbfb8..e3b90973e7 100644
--- a/lib/ansible/modules/network/nxos/nxos_snmp_location.py
+++ b/lib/ansible/modules/network/nxos/nxos_snmp_location.py
@@ -24,9 +24,11 @@ ANSIBLE_METADATA = {'status': ['preview'],
 DOCUMENTATION = '''
 ---
 module: nxos_snmp_location
+version_added: "2.2"
 short_description: Manages SNMP location information.
 description:
     - Manages SNMP location configuration.
+extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
diff --git a/lib/ansible/modules/network/nxos/nxos_static_route.py b/lib/ansible/modules/network/nxos/nxos_static_route.py
index 361347c392..5433c0ef5e 100644
--- a/lib/ansible/modules/network/nxos/nxos_static_route.py
+++ b/lib/ansible/modules/network/nxos/nxos_static_route.py
@@ -29,12 +29,13 @@ description:
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - If no vrf is supplied, vrf is set to default
-    - If state=absent, the route will be removed, regardless of the non-required parameters.
+    - If no vrf is supplied, vrf is set to default.
+    - If C(state=absent), the route will be removed, regardless of the
+      non-required parameters.
 options:
     prefix:
         description:
-            - Destination prefix of static route
+            - Destination prefix of static route.
         required: true
     next_hop:
         description:
@@ -43,7 +44,7 @@ options:
         required: true
     vrf:
         description:
-            - VRF for static route
+            - VRF for static route.
         required: false
         default: default
     tag:
@@ -58,20 +59,14 @@ options:
         default: null
     pref:
         description:
-            - Preference or administrative difference of route (range 1-255)
+            - Preference or administrative difference of route (range 1-255).
         required: false
         default: null
     state:
         description:
-            - Manage the state of the resource
+            - Manage the state of the resource.
         required: true
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 
 EXAMPLES = '''
@@ -88,18 +83,19 @@ EXAMPLES = '''
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"next_hop": "3.3.3.3", "pref": "100",
             "prefix": "192.168.20.64/24", "route_name": "testing",
             "vrf": "default"}
 existing:
     description: k/v pairs of existing configuration
+    returned: verbose mode
     type: dict
     sample: {}
 end_state:
     description: k/v pairs of configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"next_hop": "3.3.3.3", "pref": "100",
             "prefix": "192.168.20.0/24", "route_name": "testing",
@@ -117,193 +113,42 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
 from ansible.module_utils.netcfg import NetworkConfig, ConfigLine, dumps
 from ansible.module_utils.network import NetworkModule
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
+         return list()
 
-            cfg.parents = ancestors[:level]
 
-            if level > len(ancestors):
-                config.append(cfg)
+class CustomNetworkConfig(NetworkConfig):
+
+    def expand_section(self, configobj, S=None):
+        if S is None:
+            S = list()
+        S.append(configobj)
+        for child in configobj.children:
+            if child in S:
                 continue
+            self.expand_section(child, S)
+        return S
 
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
-
-
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
+    def get_object(self, path):
         for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
             if item.text == path[-1]:
                 parents = [p.text for p in item.parents]
                 if parents == path[:-1]:
                     return item
 
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
     def to_block(self, section):
         return '\n'.join([item.raw for item in section])
 
@@ -324,119 +169,6 @@ class CustomNetworkConfig(object):
             raise ValueError('path does not exist in config')
         return self.expand_section(obj)
 
-    def expand_section(self, configobj, S=None):
-        if S is None:
-            S = list()
-        S.append(configobj)
-        for child in configobj.children:
-            if child in S:
-                continue
-            self.expand_section(child, S)
-        return S
-
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
-    def get_object(self, path):
-        for item in self.items:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def get_children(self, path):
-        obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
-
 
     def add(self, lines, parents=None):
         """Adds one or lines of configuration
@@ -487,303 +219,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -809,7 +282,7 @@ def state_present(module, candidate, prefix):
 
 
 def state_absent(module, candidate, prefix):
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
     commands = list()
     parents = 'vrf context {0}'.format(module.params['vrf'])
     invoke('set_route', module, commands, prefix)
@@ -828,17 +301,13 @@ def state_absent(module, candidate, prefix):
 
 
 def fix_prefix_to_regex(prefix):
-    prefix = prefix.split('.')
-    prefix = '\.'.join(prefix)
-    prefix = prefix.split('/')
-    prefix = '\/'.join(prefix)
-
+    prefix = prefix.replace('.', '\.').replace('/', '\/')
     return prefix
 
 
 def get_existing(module, prefix, warnings):
     key_map = ['tag', 'pref', 'route_name', 'next_hop']
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
     parents = 'vrf context {0}'.format(module.params['vrf'])
     prefix_to_regex = fix_prefix_to_regex(prefix)
 
@@ -952,16 +421,17 @@ def main():
         tag=dict(type='str'),
         route_name=dict(type='str'),
         pref=dict(type='str'),
-        m_facts=dict(required=False, default=False, type='bool'),
         state=dict(choices=['absent', 'present'],
                    default='present'),
-        include_defaults=dict(default=True)
+        include_defaults=dict(default=True),
+
+        config=dict(),
+        save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
-    m_facts = module.params['m_facts']
     state = module.params['state']
 
     result = dict(changed=False)
@@ -981,16 +451,15 @@ def main():
         try:
             response = load_config(module, candidate)
             result.update(response)
-        except ShellError:
+        except Exception:
             exc = get_exception()
             module.fail_json(msg=str(exc))
     else:
         result['updates'] = []
 
     result['warnings'] = warnings
-    result['connected'] = module.connected
 
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, prefix, warnings)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_switchport.py b/lib/ansible/modules/network/nxos/nxos_switchport.py
index 2034a8f1ff..f0e06163ce 100644
--- a/lib/ansible/modules/network/nxos/nxos_switchport.py
+++ b/lib/ansible/modules/network/nxos/nxos_switchport.py
@@ -145,8 +145,8 @@ end_state:
 updates:
     description: command string sent to the device
     returned: always
-    type: string
-    sample: "interface eth1/5 ; switchport access vlan 20 ;"
+    type: list
+    sample: ["interface eth1/5", "switchport access vlan 20"]
 changed:
     description: check to see if a change was made on the device
     returned: always
diff --git a/lib/ansible/modules/network/nxos/nxos_vlan.py b/lib/ansible/modules/network/nxos/nxos_vlan.py
index 81fdfe9140..b81bc98295 100644
--- a/lib/ansible/modules/network/nxos/nxos_vlan.py
+++ b/lib/ansible/modules/network/nxos/nxos_vlan.py
@@ -13,7 +13,7 @@
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with Ansible.  If not, see <http://www.gnu.org/licenses/> .
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
 #
 
 ANSIBLE_METADATA = {'status': ['preview'],
@@ -24,51 +24,51 @@ DOCUMENTATION = '''
 ---
 module: nxos_vlan
 version_added: "2.1"
-short_description: Manages VLAN resources and attributes
+short_description: Manages VLAN resources and attributes.
 description:
-    - Manages VLAN configurations on NX-OS switches
+    - Manages VLAN configurations on NX-OS switches.
 author: Jason Edelman (@jedelman8)
 extends_documentation_fragment: nxos
 options:
     vlan_id:
         description:
-            - single vlan id
+            - Single VLAN ID.
         required: false
         default: null
     vlan_range:
         description:
-            - range of VLANs such as 2-10 or 2,5,10-15, etc.
+            - Range of VLANs such as 2-10 or 2,5,10-15, etc.
         required: false
         default: null
     name:
         description:
-            - name of VLAN
+            - Name of VLAN.
         required: false
         default: null
     vlan_state:
         description:
             - Manage the vlan operational state of the VLAN
-              (equivalent to state {active | suspend} command
+              (equivalent to state {active | suspend} command.
         required: false
         default: active
         choices: ['active','suspend']
     admin_state:
         description:
-            - Manage the vlan admin state of the VLAN equivalent
-              to shut/no shut in vlan config mode
+            - Manage the VLAN administrative state of the VLAN equivalent
+              to shut/no shut in VLAN config mode.
         required: false
         default: up
         choices: ['up','down']
     mapped_vni:
         description:
-            - The Virtual Network Identifier (VNI) id that is mapped to the
+            - The Virtual Network Identifier (VNI) ID that is mapped to the
               VLAN. Valid values are integer and keyword 'default'.
         required: false
         default: null
         version_added: "2.2"
     state:
         description:
-            - Manage the state of the resource
+            - Manage the state of the resource.
         required: false
         default: present
         choices: ['present','absent']
@@ -141,11 +141,6 @@ end_state:
     type: dict or null
     sample: {"admin_state": "down", "name": "app_vlan", "vlan_id": "20",
              "vlan_state": "suspend", "mapped_vni": "5000"}
-state:
-    description: state as sent in from the playbook
-    returned: always
-    type: string
-    sample: "present"
 updates:
     description: command string sent to the device
     returned: always
@@ -159,216 +154,32 @@ changed:
 
 '''
 
-# COMMON CODE FOR MIGRATION
-
-import re
-import time
-import collections
-import itertools
-import shlex
 import json
+import collections
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -380,14 +191,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -395,93 +198,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -533,303 +266,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -1035,6 +509,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -1042,7 +521,7 @@ def execute_show(cmds, module, command_type=None):
             response = module.execute(cmds)
     except ShellError:
         clie = get_exception()
-        module.fail_json(msg='Error sending {0}'.format(command),
+        module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
     except AttributeError:
         try:
@@ -1084,8 +563,11 @@ def main():
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
             admin_state=dict(choices=['up', 'down'], required=False),
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         mutually_exclusive=[['vlan_range', 'name'],
                                             ['vlan_id', 'vlan_range']],
                         supports_check_mode=True)
diff --git a/lib/ansible/modules/network/nxos/nxos_vpc.py b/lib/ansible/modules/network/nxos/nxos_vpc.py
index 30b9969f6d..849018cf92 100644
--- a/lib/ansible/modules/network/nxos/nxos_vpc.py
+++ b/lib/ansible/modules/network/nxos/nxos_vpc.py
@@ -149,215 +149,28 @@ import json
 import collections
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
-import json
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -369,14 +182,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -384,93 +189,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -522,303 +257,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -865,6 +341,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -1092,9 +573,11 @@ def main():
             auto_recovery=dict(required=True, type='bool'),
             delay_restore=dict(required=False, type='str'),
             state=dict(choices=['absent', 'present'], default='present'),
-            include_defaults=dict(default=False)
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     domain = module.params['domain']
diff --git a/lib/ansible/modules/network/nxos/nxos_vpc_interface.py b/lib/ansible/modules/network/nxos/nxos_vpc_interface.py
index 2ead2ca3f3..de5a660cf0 100644
--- a/lib/ansible/modules/network/nxos/nxos_vpc_interface.py
+++ b/lib/ansible/modules/network/nxos/nxos_vpc_interface.py
@@ -41,11 +41,11 @@ notes:
 options:
     portchannel:
         description:
-            - group number of the portchannel that will be configured
+            - Group number of the portchannel that will be configured.
         required: true
     vpc:
         description:
-            - vpc group/id that will be configured on associated portchannel
+            - VPC group/id that will be configured on associated portchannel.
         required: false
         default: null
     peer_link:
@@ -55,7 +55,7 @@ options:
         default: null
     state:
         description:
-            - Manages desired state of the resource
+            - Manages desired state of the resource.
         required: true
         choices: ['present','absent']
 '''
@@ -96,216 +96,33 @@ changed:
     sample: true
 '''
 
-# COMMON CODE FOR MIGRATION
 
-import re
-import time
 import collections
-import itertools
-import shlex
 import json
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -317,14 +134,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -332,93 +141,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -470,303 +209,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -776,7 +256,7 @@ def load_config(module, candidate):
 
 def execute_config_command(commands, module):
     try:
-        output = module.configure(commands)
+        response = module.configure(commands)
     except ShellError:
         clie = get_exception()
         module.fail_json(msg='Error sending CLI commands',
@@ -812,6 +292,11 @@ def get_cli_body_ssh(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -996,8 +481,11 @@ def main():
             vpc=dict(required=False, type='str'),
             peer_link=dict(required=False, type='bool'),
             state=dict(choices=['absent', 'present'], default='present'),
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         mutually_exclusive=[['vpc', 'peer_link']],
                         supports_check_mode=True)
 
diff --git a/lib/ansible/modules/network/nxos/nxos_vrf.py b/lib/ansible/modules/network/nxos/nxos_vrf.py
index 5f88f1b8d1..217007b54f 100644
--- a/lib/ansible/modules/network/nxos/nxos_vrf.py
+++ b/lib/ansible/modules/network/nxos/nxos_vrf.py
@@ -24,9 +24,9 @@ DOCUMENTATION = '''
 ---
 module: nxos_vrf
 version_added: "2.1"
-short_description: Manages global VRF configuration
+short_description: Manages global VRF configuration.
 description:
-    - Manages global VRF configuration
+    - Manages global VRF configuration.
 extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
@@ -34,20 +34,20 @@ author:
 notes:
     - Cisco NX-OS creates the default VRF by itself. Therefore,
       you're not allowed to use default as I(vrf) name in this module.
-    - I(vrf) name must be shorter than 32 chars.
+    - C(vrf) name must be shorter than 32 chars.
     - VRF names are not case sensible in NX-OS. Anyway, the name is stored
       just like it's inserted by the user and it'll not be changed again
-      unless the VRF is removed and re-created. i.e. I(vrf=NTC) will create
-      a VRF named NTC, but running it again with I(vrf=ntc) will not cause
+      unless the VRF is removed and re-created. i.e. C(vrf=NTC) will create
+      a VRF named NTC, but running it again with C(vrf=ntc) will not cause
       a configuration change.
 options:
     vrf:
         description:
-            - Name of VRF to be managed
+            - Name of VRF to be managed.
         required: true
     admin_state:
         description:
-            - Administrative state of the VRF
+            - Administrative state of the VRF.
         required: false
         default: up
         choices: ['up','down']
@@ -68,13 +68,13 @@ options:
         version_added: "2.2"
     state:
         description:
-            - Manages desired state of the resource
+            - Manages desired state of the resource.
         required: false
         default: present
         choices: ['present','absent']
     description:
         description:
-            - Description of the VRF
+            - Description of the VRF.
         required: false
         default: null
 '''
@@ -121,13 +121,7 @@ changed:
 import json
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
-import json
 
 import ansible.module_utils.nxos
 from ansible.module_utils.basic import get_exception
@@ -135,200 +129,17 @@ from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
 from ansible.module_utils.shell import ShellError
 from ansible.module_utils.network import NetworkModule
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
 
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -340,14 +151,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -355,93 +158,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -493,303 +226,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -834,6 +308,11 @@ def get_cli_body_ssh_vrf(module, command, response):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -974,8 +453,11 @@ def main():
                              required=False),
             state=dict(default='present', choices=['present', 'absent'],
                        required=False),
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     vrf = module.params['vrf']
diff --git a/lib/ansible/modules/network/nxos/nxos_vrf_af.py b/lib/ansible/modules/network/nxos/nxos_vrf_af.py
index 754fc962d3..f0b008476f 100644
--- a/lib/ansible/modules/network/nxos/nxos_vrf_af.py
+++ b/lib/ansible/modules/network/nxos/nxos_vrf_af.py
@@ -22,16 +22,15 @@ ANSIBLE_METADATA = {'status': ['preview'],
 
 DOCUMENTATION = '''
 ---
-module: nxos_vxlan_vtep_vni
+module: nxos_vrf_af
 version_added: "2.2"
-short_description: Creates a Virtual Network Identifier member (VNI)
+short_description: Manages VRF AF.
 description:
-    - Creates a Virtual Network Identifier member (VNI) for an NVE
-      overlay interface.
+    - Manages VRF AF
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - default, where supported, restores params default value
+    - Default, where supported, restores params default value.
 options:
     vrf:
         description:
@@ -58,16 +57,11 @@ options:
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or
+              not on the device.
         required: false
         default: present
         choices: ['present','absent']
-    m_facts:
-        description:
-            - Used to print module facts
-        required: false
-        default: false
-        choices: ['true','false']
 '''
 EXAMPLES = '''
 - nxos_vrf_af:
@@ -78,22 +72,22 @@ EXAMPLES = '''
     password: "{{ pwd }}"
     host: "{{ inventory_hostname }}"
 '''
-
 RETURN = '''
 proposed:
     description: k/v pairs of parameters passed into module
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"afi": "ipv4", "route_target_both_auto_evpn": true,
             "safi": "unicast", "vrf": "test"}
 existing:
     description: k/v pairs of existing configuration
+    returned: verbose mode
     type: dict
     sample: {"afi": "ipv4", "route_target_both_auto_evpn": false,
             "safi": "unicast", "vrf": "test"}
 end_state:
     description: k/v pairs of configuration after module execution
-    returned: always
+    returned: verbose mode
     type: dict
     sample: {"afi": "ipv4", "route_target_both_auto_evpn": true,
             "safi": "unicast", "vrf": "test"}
@@ -111,214 +105,28 @@ changed:
 '''
 
 # COMMON CODE FOR MIGRATION
-
 import re
-import time
-import collections
-import itertools
-import shlex
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -330,14 +138,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -345,93 +145,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -483,303 +213,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -819,7 +290,7 @@ def get_value(arg, config, module):
 
 def get_existing(module, args):
     existing = {}
-    netcfg = custom_get_config(module)
+    netcfg = get_config(module)
 
     parents = ['vrf context {0}'.format(module.params['vrf'])]
     parents.append('address-family {0} {1}'.format(module.params['afi'],
@@ -903,10 +374,11 @@ def main():
             m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
-            include_defaults=dict(default=False)
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    argument_spec.update(nxos_argument_spec)
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     state = module.params['state']
@@ -948,7 +420,7 @@ def main():
         result['updates'] = []
 
     result['connected'] = module.connected
-    if module.params['m_facts']:
+    if module._verbosity > 0:
         end_state = invoke('get_existing', module, args)
         result['end_state'] = end_state
         result['existing'] = existing
diff --git a/lib/ansible/modules/network/nxos/nxos_vrf_interface.py b/lib/ansible/modules/network/nxos/nxos_vrf_interface.py
index 11a90a8091..ca04148496 100644
--- a/lib/ansible/modules/network/nxos/nxos_vrf_interface.py
+++ b/lib/ansible/modules/network/nxos/nxos_vrf_interface.py
@@ -24,30 +24,32 @@ DOCUMENTATION = '''
 ---
 module: nxos_vrf_interface
 version_added: "2.1"
-short_description: Manages interface specific VRF configuration
+short_description: Manages interface specific VRF configuration.
 description:
-    - Manages interface specific VRF configuration
+    - Manages interface specific VRF configuration.
 extends_documentation_fragment: nxos
-author: Jason Edelman (@jedelman8), Gabriele Gerbino (@GGabriele)
+author:
+    - Jason Edelman (@jedelman8)
+    - Gabriele Gerbino (@GGabriele)
 notes:
     - VRF needs to be added globally with M(nxos_vrf) before
-      adding a VRF to an interface
+      adding a VRF to an interface.
     - Remove a VRF from an interface will still remove
-      all L3 attributes just as it does from CLI
+      all L3 attributes just as it does from CLI.
     - VRF is not read from an interface until IP address is
-      configured on that interface
+      configured on that interface.
 options:
     vrf:
         description:
-            - Name of VRF to be managed
+            - Name of VRF to be managed.
         required: true
     interface:
         description:
-            - Full name of interface to be managed, i.e. Ethernet1/1
+            - Full name of interface to be managed, i.e. Ethernet1/1.
         required: true
     state:
         description:
-            - Manages desired state of the resource
+            - Manages desired state of the resource.
         required: false
         default: present
         choices: ['present','absent']
@@ -96,216 +98,32 @@ changed:
     sample: true
 '''
 
-# COMMON CODE FOR MIGRATION
-
-import re
-import time
-import collections
-import itertools
-import shlex
 import json
+import collections
 
-from ansible.module_utils.basic import AnsibleModule, env_fallback, get_exception
-from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
-from ansible.module_utils.shell import Shell, ShellError, HAS_PARAMIKO
-from ansible.module_utils.netcfg import parse
-from ansible.module_utils.urls import fetch_url
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
 
 
-DEFAULT_COMMENT_TOKENS = ['#', '!']
-
-class ConfigLine(object):
-
-    def __init__(self, text):
-        self.text = text
-        self.children = list()
-        self.parents = list()
-        self.raw = None
-
-    @property
-    def line(self):
-        line = ['set']
-        line.extend([p.text for p in self.parents])
-        line.append(self.text)
-        return ' '.join(line)
-
-    def __str__(self):
-        return self.raw
-
-    def __eq__(self, other):
-        if self.text == other.text:
-            return self.parents == other.parents
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-def ignore_line(text, tokens=None):
-    for item in (tokens or DEFAULT_COMMENT_TOKENS):
-        if text.startswith(item):
-            return True
-
-def get_next(iterable):
-    item, next_item = itertools.tee(iterable, 2)
-    next_item = itertools.islice(next_item, 1, None)
-    return itertools.izip_longest(item, next_item)
-
-def parse(lines, indent, comment_tokens=None):
-    toplevel = re.compile(r'\S')
-    childline = re.compile(r'^\s*(.+)$')
-
-    ancestors = list()
-    config = list()
-
-    for line in str(lines).split('\n'):
-        text = str(re.sub(r'([{};])', '', line)).strip()
-
-        cfg = ConfigLine(text)
-        cfg.raw = line
-
-        if not text or ignore_line(text, comment_tokens):
-            continue
-
-        # handle top level commands
-        if toplevel.match(line):
-            ancestors = [cfg]
-
-        # handle sub level commands
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
         else:
-            match = childline.match(line)
-            line_indent = match.start(1)
-            level = int(line_indent / indent)
-            parent_level = level - 1
-
-            cfg.parents = ancestors[:level]
-
-            if level > len(ancestors):
-                config.append(cfg)
-                continue
-
-            for i in range(level, len(ancestors)):
-                ancestors.pop()
-
-            ancestors.append(cfg)
-            ancestors[parent_level].children.append(cfg)
-
-        config.append(cfg)
-
-    return config
+         return list()
 
 
-class CustomNetworkConfig(object):
-
-    def __init__(self, indent=None, contents=None, device_os=None):
-        self.indent = indent or 1
-        self._config = list()
-        self._device_os = device_os
-
-        if contents:
-            self.load(contents)
-
-    @property
-    def items(self):
-        return self._config
-
-    @property
-    def lines(self):
-        lines = list()
-        for item, next_item in get_next(self.items):
-            if next_item is None:
-                lines.append(item.line)
-            elif not next_item.line.startswith(item.line):
-                lines.append(item.line)
-        return lines
-
-    def __str__(self):
-        text = ''
-        for item in self.items:
-            if not item.parents:
-                expand = self.get_section(item.text)
-                text += '%s\n' % self.get_section(item.text)
-        return str(text).strip()
-
-    def load(self, contents):
-        self._config = parse(contents, indent=self.indent)
-
-    def load_from_file(self, filename):
-        self.load(open(filename).read())
-
-    def get(self, path):
-        if isinstance(path, basestring):
-            path = [path]
-        for item in self._config:
-            if item.text == path[-1]:
-                parents = [p.text for p in item.parents]
-                if parents == path[:-1]:
-                    return item
-
-    def search(self, regexp, path=None):
-        regex = re.compile(r'^%s' % regexp, re.M)
-
-        if path:
-            parent = self.get(path)
-            if not parent or not parent.children:
-                return
-            children = [c.text for c in parent.children]
-            data = '\n'.join(children)
-        else:
-            data = str(self)
-
-        match = regex.search(data)
-        if match:
-            if match.groups():
-                values = match.groupdict().values()
-                groups = list(set(match.groups()).difference(values))
-                return (groups, match.groupdict())
-            else:
-                return match.group()
-
-    def findall(self, regexp):
-        regexp = r'%s' % regexp
-        return re.findall(regexp, str(self))
-
-    def expand(self, obj, items):
-        block = [item.raw for item in obj.parents]
-        block.append(obj.raw)
-
-        current_level = items
-        for b in block:
-            if b not in current_level:
-                current_level[b] = collections.OrderedDict()
-            current_level = current_level[b]
-        for c in obj.children:
-            if c.raw not in current_level:
-                current_level[c.raw] = collections.OrderedDict()
-
-    def to_lines(self, section):
-        lines = list()
-        for entry in section[1:]:
-            line = ['set']
-            line.extend([p.text for p in entry.parents])
-            line.append(entry.text)
-            lines.append(' '.join(line))
-        return lines
-
-    def to_block(self, section):
-        return '\n'.join([item.raw for item in section])
-
-    def get_section(self, path):
-        try:
-            section = self.get_section_objects(path)
-            if self._device_os == 'junos':
-                return self.to_lines(section)
-            return self.to_block(section)
-        except ValueError:
-            return list()
-
-    def get_section_objects(self, path):
-        if not isinstance(path, list):
-            path = [path]
-        obj = self.get_object(path)
-        if not obj:
-            raise ValueError('path does not exist in config')
-        return self.expand_section(obj)
+class CustomNetworkConfig(NetworkConfig):
 
     def expand_section(self, configobj, S=None):
         if S is None:
@@ -317,14 +135,6 @@ class CustomNetworkConfig(object):
             self.expand_section(child, S)
         return S
 
-    def flatten(self, data, obj=None):
-        if obj is None:
-            obj = list()
-        for k, v in data.items():
-            obj.append(k)
-            self.flatten(v, obj)
-        return obj
-
     def get_object(self, path):
         for item in self.items:
             if item.text == path[-1]:
@@ -332,93 +142,23 @@ class CustomNetworkConfig(object):
                 if parents == path[:-1]:
                     return item
 
-    def get_children(self, path):
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
         obj = self.get_object(path)
-        if obj:
-            return obj.children
-
-    def difference(self, other, path=None, match='line', replace='line'):
-        updates = list()
-
-        config = self.items
-        if path:
-            config = self.get_children(path) or list()
-
-        if match == 'line':
-            for item in config:
-                if item not in other.items:
-                    updates.append(item)
-
-        elif match == 'strict':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            for index, item in enumerate(config):
-                try:
-                    if item != current[index]:
-                        updates.append(item)
-                except IndexError:
-                    updates.append(item)
-
-        elif match == 'exact':
-            if path:
-                current = other.get_children(path) or list()
-            else:
-                current = other.items
-
-            if len(current) != len(config):
-                updates.extend(config)
-            else:
-                for ours, theirs in itertools.izip(config, current):
-                    if ours != theirs:
-                        updates.extend(config)
-                        break
-
-        if self._device_os == 'junos':
-            return updates
-
-        diffs = collections.OrderedDict()
-        for update in updates:
-            if replace == 'block' and update.parents:
-                update = update.parents[-1]
-            self.expand(update, diffs)
-
-        return self.flatten(diffs)
-
-    def replace(self, replace, text=None, regex=None, parents=None,
-            add_if_missing=False, ignore_whitespace=False):
-        match = None
-
-        parents = parents or list()
-        if text is None and regex is None:
-            raise ValueError('missing required arguments')
-
-        if not regex:
-            regex = ['^%s$' % text]
-
-        patterns = [re.compile(r, re.I) for r in to_list(regex)]
-
-        for item in self.items:
-            for regexp in patterns:
-                if ignore_whitespace is True:
-                    string = item.text
-                else:
-                    string = item.raw
-                if regexp.search(item.text):
-                    if item.text != replace:
-                        if parents == [p.text for p in item.parents]:
-                            match = item
-                            break
-
-        if match:
-            match.text = replace
-            indent = len(match.raw) - len(match.raw.lstrip())
-            match.raw = replace.rjust(len(replace) + indent)
-
-        elif add_if_missing:
-            self.add(replace, parents=parents)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
 
 
     def add(self, lines, parents=None):
@@ -470,303 +210,44 @@ class CustomNetworkConfig(object):
                     self.items.append(item)
 
 
-def argument_spec():
-    return dict(
-        # config options
-        running_config=dict(aliases=['config']),
-        save_config=dict(type='bool', default=False, aliases=['save'])
-    )
-nxos_argument_spec = argument_spec()
-
-
-NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)
-
-NET_COMMON_ARGS = dict(
-    host=dict(required=True),
-    port=dict(type='int'),
-    username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
-    password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
-    ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
-    transport=dict(default='cli', choices=['cli', 'nxapi']),
-    use_ssl=dict(default=False, type='bool'),
-    validate_certs=dict(default=True, type='bool'),
-    provider=dict(type='dict'),
-    timeout=dict(default=10, type='int')
-)
-
-NXAPI_COMMAND_TYPES = ['cli_show', 'cli_show_ascii', 'cli_conf', 'bash']
-
-NXAPI_ENCODINGS = ['json', 'xml']
-
-CLI_PROMPTS_RE = [
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'),
-    re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$')
-]
-
-CLI_ERRORS_RE = [
-    re.compile(r"% ?Error"),
-    re.compile(r"^% \w+", re.M),
-    re.compile(r"% ?Bad secret"),
-    re.compile(r"invalid input", re.I),
-    re.compile(r"(?:incomplete|ambiguous) command", re.I),
-    re.compile(r"connection timed out", re.I),
-    re.compile(r"[^\r\n]+ not found", re.I),
-    re.compile(r"'[^']' +returned error code: ?\d+"),
-    re.compile(r"syntax error"),
-    re.compile(r"unknown command")
-]
-
-
-def to_list(val):
-    if isinstance(val, (list, tuple)):
-        return list(val)
-    elif val is not None:
-        return [val]
-    else:
-        return list()
-
-
-class Nxapi(object):
-
-    def __init__(self, module):
-        self.module = module
-
-        # sets the module_utils/urls.py req parameters
-        self.module.params['url_username'] = module.params['username']
-        self.module.params['url_password'] = module.params['password']
-
-        self.url = None
-        self._nxapi_auth = None
-
-    def _get_body(self, commands, command_type, encoding, version='1.0', chunk='0', sid=None):
-        """Encodes a NXAPI JSON request message
-        """
-        if isinstance(commands, (list, set, tuple)):
-            commands = ' ;'.join(commands)
-
-        if encoding not in NXAPI_ENCODINGS:
-            msg = 'invalid encoding, received %s, exceped one of %s' % \
-                    (encoding, ','.join(NXAPI_ENCODINGS))
-            self.module_fail_json(msg=msg)
-
-        msg = {
-            'version': version,
-            'type': command_type,
-            'chunk': chunk,
-            'sid': sid,
-            'input': commands,
-            'output_format': encoding
-        }
-        return dict(ins_api=msg)
-
-    def connect(self):
-        host = self.module.params['host']
-        port = self.module.params['port']
-
-        if self.module.params['use_ssl']:
-            proto = 'https'
-            if not port:
-                port = 443
-        else:
-            proto = 'http'
-            if not port:
-                port = 80
-
-        self.url = '%s://%s:%s/ins' % (proto, host, port)
-
-    def send(self, commands, command_type='cli_show_ascii', encoding='json'):
-        """Send commands to the device.
-        """
-        clist = to_list(commands)
-
-        if command_type not in NXAPI_COMMAND_TYPES:
-            msg = 'invalid command_type, received %s, exceped one of %s' % \
-                    (command_type, ','.join(NXAPI_COMMAND_TYPES))
-            self.module_fail_json(msg=msg)
-
-        data = self._get_body(clist, command_type, encoding)
-        data = self.module.jsonify(data)
-
-        headers = {'Content-Type': 'application/json'}
-        if self._nxapi_auth:
-            headers['Cookie'] = self._nxapi_auth
-
-        response, headers = fetch_url(self.module, self.url, data=data,
-                headers=headers, method='POST')
-
-        self._nxapi_auth = headers.get('set-cookie')
-
-        if headers['status'] != 200:
-            self.module.fail_json(**headers)
-
-        response = self.module.from_json(response.read())
-        result = list()
-
-        output = response['ins_api']['outputs']['output']
-        for item in to_list(output):
-            if item['code'] != '200':
-                self.module.fail_json(**item)
-            else:
-                result.append(item['body'])
-
-        return result
-
-
-class Cli(object):
-
-    def __init__(self, module):
-        self.module = module
-        self.shell = None
-
-    def connect(self, **kwargs):
-        host = self.module.params['host']
-        port = self.module.params['port'] or 22
-
-        username = self.module.params['username']
-        password = self.module.params['password']
-        timeout = self.module.params['timeout']
-        key_filename = self.module.params['ssh_keyfile']
-
-        allow_agent = (key_filename is not None) or (key_filename is None and password is None)
-
+def get_network_module(**kwargs):
         try:
-            self.shell = Shell(kickstart=False, prompts_re=CLI_PROMPTS_RE,
-                    errors_re=CLI_ERRORS_RE)
-            self.shell.open(host, port=port, username=username,
-                    password=password, key_filename=key_filename,
-                    allow_agent=allow_agent, timeout=timeout)
-        except ShellError:
-            e = get_exception()
-            msg = 'failed to connect to %s:%s - %s' % (host, port, str(e))
-            self.module.fail_json(msg=msg)
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
 
-    def send(self, commands, encoding='text'):
-        try:
-            return self.shell.send(commands)
-        except ShellError:
-            e = get_exception()
-            self.module.fail_json(msg=e.message, commands=commands)
-
-
-class NetworkModule(AnsibleModule):
-
-    def __init__(self, *args, **kwargs):
-        super(NetworkModule, self).__init__(*args, **kwargs)
-        self.connection = None
-        self._config = None
-        self._connected = False
-
-    @property
-    def connected(self):
-        return self._connected
-
-    @property
-    def config(self):
-        if not self._config:
-            self._config = self.get_config()
-        return self._config
-
-    def _load_params(self):
-        super(NetworkModule, self)._load_params()
-        provider = self.params.get('provider') or dict()
-        for key, value in provider.items():
-            if key in NET_COMMON_ARGS:
-                if self.params.get(key) is None and value is not None:
-                    self.params[key] = value
-
-    def connect(self):
-        cls = globals().get(str(self.params['transport']).capitalize())
-        try:
-            self.connection = cls(self)
-        except TypeError:
-            e = get_exception()
-            self.fail_json(msg=e.message)
-
-        self.connection.connect()
-
-        if self.params['transport'] == 'cli':
-            self.connection.send('terminal length 0')
-
-        self._connected = True
-
-    def configure(self, commands):
-        commands = to_list(commands)
-        if self.params['transport'] == 'cli':
-            return self.configure_cli(commands)
-        else:
-            return self.execute(commands, command_type='cli_conf')
-
-    def configure_cli(self, commands):
-        commands = to_list(commands)
-        commands.insert(0, 'configure')
-        responses = self.execute(commands)
-        responses.pop(0)
-        return responses
-
-    def execute(self, commands, **kwargs):
-        if not self.connected:
-            self.connect()
-        return self.connection.send(commands, **kwargs)
-
-    def disconnect(self):
-        self.connection.close()
-        self._connected = False
-
-    def parse_config(self, cfg):
-        return parse(cfg, indent=2)
-
-    def get_config(self):
-        cmd = 'show running-config'
-        if self.params.get('include_defaults'):
-            cmd += ' all'
-        response = self.execute(cmd)
-        return response[0]
-
-
-def get_module(**kwargs):
-    """Return instance of NetworkModule
-    """
-    argument_spec = NET_COMMON_ARGS.copy()
-    if kwargs.get('argument_spec'):
-        argument_spec.update(kwargs['argument_spec'])
-    kwargs['argument_spec'] = argument_spec
-
-    module = NetworkModule(**kwargs)
-
-    if module.params['transport'] == 'cli' and not HAS_PARAMIKO:
-        module.fail_json(msg='paramiko is required but does not appear to be installed')
-
-    return module
-
-
-def custom_get_config(module, include_defaults=False):
-    config = module.params['running_config']
+def get_config(module, include_defaults=False):
+    config = module.params['config']
     if not config:
-        cmd = 'show running-config'
-        if module.params['include_defaults']:
-            cmd += ' all'
-        if module.params['transport'] == 'nxapi':
-            config = module.execute([cmd], command_type='cli_show_ascii')[0]
-        else:
-            config = module.execute([cmd])[0]
-
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
     return CustomNetworkConfig(indent=2, contents=config)
 
 def load_config(module, candidate):
-    config = custom_get_config(module)
+    config = get_config(module)
 
     commands = candidate.difference(config)
     commands = [str(c).strip() for c in commands]
 
-    save_config = module.params['save_config']
+    save_config = module.params['save']
 
     result = dict(changed=False)
 
     if commands:
         if not module.check_mode:
+            try:
             module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
             if save_config:
+                try:
                 module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
 
         result['changed'] = True
         result['updates'] = commands
@@ -810,6 +291,11 @@ def get_cli_body_ssh_vrf_interface(command, response, module):
 
 
 def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
     try:
         if command_type:
             response = module.execute(cmds, command_type=command_type)
@@ -817,7 +303,7 @@ def execute_show(cmds, module, command_type=None):
             response = module.execute(cmds)
     except ShellError:
         clie = get_exception()
-        module.fail_json(msg='Error sending {0}'.format(command),
+        module.fail_json(msg='Error sending {0}'.format(cmds),
                          error=str(clie))
     except AttributeError:
         try:
@@ -936,8 +422,11 @@ def main():
             interface=dict(type='str', required=True),
             state=dict(default='present', choices=['present', 'absent'],
                        required=False),
+            include_defaults=dict(default=False),
+            config=dict(),
+            save=dict(type='bool', default=False)
     )
-    module = get_module(argument_spec=argument_spec,
+    module = get_network_module(argument_spec=argument_spec,
                         supports_check_mode=True)
 
     vrf = module.params['vrf']
diff --git a/lib/ansible/modules/network/nxos/nxos_vrrp.py b/lib/ansible/modules/network/nxos/nxos_vrrp.py
index bf820ed9d8..58c04a8367 100644
--- a/lib/ansible/modules/network/nxos/nxos_vrrp.py
+++ b/lib/ansible/modules/network/nxos/nxos_vrrp.py
@@ -25,53 +25,53 @@ DOCUMENTATION = '''
 ---
 module: nxos_vrrp
 version_added: "2.1"
-short_description: Manages VRRP configuration on NX-OS switches
+short_description: Manages VRRP configuration on NX-OS switches.
 description:
-    - Manages VRRP configuration on NX-OS switches
+    - Manages VRRP configuration on NX-OS switches.
 extends_documentation_fragment: nxos
 author:
     - Jason Edelman (@jedelman8)
     - Gabriele Gerbino (@GGabriele)
 notes:
-    - VRRP feature needs to be enabled first on the system
-    - SVIs must exist before using this module
-    - Interface must be a L3 port before using this module
-    - I(state)=absent removes the vrrp group if it exists on the device
-    - VRRP cannot be configured on loopback interfaces
+    - VRRP feature needs to be enabled first on the system.
+    - SVIs must exist before using this module.
+    - Interface must be a L3 port before using this module.
+    - C(state=absent) removes the VRRP group if it exists on the device.
+    - VRRP cannot be configured on loopback interfaces.
 options:
     group:
         description:
-            - VRRP group number
+            - VRRP group number.
         required: true
     interface:
         description:
-            - Full name of interface that is being managed for VRRP
+            - Full name of interface that is being managed for VRRP.
         required: true
     priority:
         description:
-            - VRRP priority
+            - VRRP priority.
         required: false
         default: null
     vip:
         description:
-            - VRRP virtual IP address
+            - VRRP virtual IP address.
         required: false
         default: null
     authentication:
         description:
-            - clear text authentication string
+            - Clear text authentication string.
         required: false
         default: null
     admin_state:
         description:
-            - Used to enable or disable the VRRP process
+            - Used to enable or disable the VRRP process.
         required: false
         choices: ['shutdown', 'no shutdown']
         default: no shutdown
         version_added: "2.2"
     state:
         description:
-            - Specify desired state of the resource
+            - Specify desired state of the resource.
         required: false
         default: present
         choices: ['present','absent']
diff --git a/lib/ansible/modules/network/nxos/nxos_vtp_password.py b/lib/ansible/modules/network/nxos/nxos_vtp_password.py
index 1051f64bc9..12c142c2fc 100644
--- a/lib/ansible/modules/network/nxos/nxos_vtp_password.py
+++ b/lib/ansible/modules/network/nxos/nxos_vtp_password.py
@@ -25,9 +25,9 @@ DOCUMENTATION = '''
 
 module: nxos_vtp
 version_added: "2.2"
-short_description: Manages VTP configuration.
+short_description: Manages VTP password configuration.
 description:
-    - Manages VTP configuration
+    - Manages VTP password configuration.
 extends_documentation_fragment: nxos
 author:
     - Gabriele Gerbino (@GGabriele)
diff --git a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py
index 973c175a04..6d29597cd2 100644
--- a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py
+++ b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py
@@ -24,7 +24,7 @@ DOCUMENTATION = '''
 ---
 module: nxos_vxlan_vtep
 version_added: "2.2"
-short_description: Manages VXLAN Network Virtualization Endpoint (NVE)
+short_description: Manages VXLAN Network Virtualization Endpoint (NVE).
 description:
     - Manages VXLAN Network Virtualization Endpoint (NVE) overlay interface
       that terminates VXLAN tunnels.
@@ -32,13 +32,13 @@ author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
     - The module is used to manage NVE properties, not to create NVE
-      interfaces. Use nxos_interface if you wish to do so.
-    - State 'absent' removes the interface
-    - default, where supported, restores params default value
+      interfaces. Use M(nxos_interface) if you wish to do so.
+    - C(state=absent) removes the interface.
+    - Default, where supported, restores params default value.
 options:
     interface:
         description:
-            - Interface name for the VXLAN Network Virtualization Endpoint
+            - Interface name for the VXLAN Network Virtualization Endpoint.
         required: true
     description:
         description:
@@ -71,7 +71,8 @@ options:
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
diff --git a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py
index 545b62f3b8..cf354d59c4 100644
--- a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py
+++ b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py
@@ -31,11 +31,11 @@ description:
 author: Gabriele Gerbino (@GGabriele)
 extends_documentation_fragment: nxos
 notes:
-    - default, where supported, restores params default value
+    - default, where supported, restores params default value.
 options:
     interface:
         description:
-            - Interface name for the VXLAN Network Virtualization Endpoint
+            - Interface name for the VXLAN Network Virtualization Endpoint.
         required: true
     vni:
         description:
@@ -77,7 +77,8 @@ options:
         default: null
     state:
         description:
-            - Determines whether the config should be present or not on the device.
+            - Determines whether the config should be present or not
+              on the device.
         required: false
         default: present
         choices: ['present','absent']
@@ -489,7 +490,6 @@ def main():
             suppress_arp=dict(required=False, type='bool'),
             ingress_replication=dict(required=False, type='str',
                                      choices=['bgp', 'static', 'default']),
-            m_facts=dict(required=False, default=False, type='bool'),
             state=dict(choices=['present', 'absent'], default='present',
                        required=False),
             include_defaults=dict(default=True),
diff --git a/lib/ansible/modules/packaging/os/rhn_register.py b/lib/ansible/modules/packaging/os/rhn_register.py
index e5fc77147d..c228f0b1b7 100644
--- a/lib/ansible/modules/packaging/os/rhn_register.py
+++ b/lib/ansible/modules/packaging/os/rhn_register.py
@@ -71,13 +71,13 @@ options:
             - supply a custom ssl CA certificate file for use with registration
         required: False
         default: None
-        version_added: "2.0"
+        version_added: "2.1"
     systemorgid:
         description:
             - supply an organizational id for use with registration
         required: False
         default: None
-        version_added: "2.0"
+        version_added: "2.1"
     channels:
         description:
             - Optionally specify a list of comma-separated channels to subscribe to upon successful registration.
diff --git a/lib/ansible/modules/packaging/os/rpm_key.py b/lib/ansible/modules/packaging/os/rpm_key.py
index 83d5e967f8..9cb058c56a 100644
--- a/lib/ansible/modules/packaging/os/rpm_key.py
+++ b/lib/ansible/modules/packaging/os/rpm_key.py
@@ -154,7 +154,7 @@ class RpmKey:
             gpg = self.module.get_bin_path('gpg2')
 
         if not gpg:
-            self.json_fail(msg="rpm_key requires a command lne gpg or gpg2, none found")
+            self.json_fail(msg="rpm_key requires a command line gpg or gpg2, none found")
 
         stdout, stderr = self.execute_command([gpg, '--no-tty', '--batch', '--with-colons', '--fixed-list-mode', '--list-packets', keyfile])
         for line in stdout.splitlines():
diff --git a/lib/ansible/modules/packaging/os/yum.py b/lib/ansible/modules/packaging/os/yum.py
index 53f4c24804..18e7171390 100644
--- a/lib/ansible/modules/packaging/os/yum.py
+++ b/lib/ansible/modules/packaging/os/yum.py
@@ -56,7 +56,7 @@ options:
     aliases: [ 'pkg' ]
   exclude:
     description:
-      - "Package name(s) to exlude when state=present, or latest
+      - "Package name(s) to exclude when state=present, or latest"
     required: false
     version_added: "2.0"
     default: null
diff --git a/lib/ansible/modules/system/cron.py b/lib/ansible/modules/system/cron.py
index 4306ea12bf..6e87147f39 100644
--- a/lib/ansible/modules/system/cron.py
+++ b/lib/ansible/modules/system/cron.py
@@ -137,7 +137,7 @@ options:
   disabled:
     description:
       - If the job should be disabled (commented out) in the crontab. Only has effect if state=present
-    version_added: "1.9"
+    version_added: "2.0"
     required: false
     default: false
   env:
@@ -152,14 +152,14 @@ options:
     description:
       - Used with C(state=present) and C(env). If specified, the environment variable will be
         inserted after the declaration of specified environment variable.
-    version_added: "2"
+    version_added: "2.1"
     required: false
     default: null
   insertbefore:
     description:
       - Used with C(state=present) and C(env). If specified, the environment variable will be
         inserted before the declaration of specified environment variable.
-    version_added: "2"
+    version_added: "2.1"
     required: false
     default: null
 requirements:
diff --git a/lib/ansible/modules/system/setup.py b/lib/ansible/modules/system/setup.py
index 39186bfa35..81bbf43ddb 100644
--- a/lib/ansible/modules/system/setup.py
+++ b/lib/ansible/modules/system/setup.py
@@ -80,7 +80,7 @@ notes:
     - If the target host is Windows, you will not currently have the ability to use
       C(filter) as this is provided by a simpler implementation of the module.
     - If the target host is Windows you can now use C(fact_path). Make sure that this path 
-      exists on the target host. Files in this path MUST be PowerShell scripts (*.ps1) and 
+      exists on the target host. Files in this path MUST be PowerShell scripts (``*.ps1``) and 
       their output must be formattable in JSON (Ansible will take care of this). Test the 
       output of your scripts.
       This option was added in Ansible 2.1.
diff --git a/lib/ansible/modules/system/user.py b/lib/ansible/modules/system/user.py
index f812e4eb66..ed5503583a 100644
--- a/lib/ansible/modules/system/user.py
+++ b/lib/ansible/modules/system/user.py
@@ -57,6 +57,7 @@ options:
         required: false
         description:
             - Optionally sets the seuser type (user_u) on selinux enabled systems.
+        version_added: "2.1"
     group:
         required: false
         description:
diff --git a/lib/ansible/modules/windows/win_lineinfile.py b/lib/ansible/modules/windows/win_lineinfile.py
index a657a64d60..df250d6d41 100644
--- a/lib/ansible/modules/windows/win_lineinfile.py
+++ b/lib/ansible/modules/windows/win_lineinfile.py
@@ -23,13 +23,11 @@ ANSIBLE_METADATA = {'status': ['preview'],
 DOCUMENTATION = """
 ---
 module: win_lineinfile
-author: Brian Lloyd (brian.d.lloyd@gmail.com)
-short_description: Ensure a particular line is in a file, or replace an
-                   existing line using a back-referenced regular expression.
+author: "Brian Lloyd <brian.d.lloyd@gmail.com>"
+short_description: Ensure a particular line is in a file, or replace an existing line using a back-referenced regular expression.
 description:
   - This module will search a file for a line, and ensure that it is present or absent.
-  - This is primarily useful when you want to change a single line in
-    a file only.
+  - This is primarily useful when you want to change a single line in a file only.
 version_added: "2.0"
 options:
   dest:
@@ -51,21 +49,14 @@ options:
   line:
     required: false
     description:
-      - Required for C(state=present). The line to insert/replace into the
-        file. If C(backrefs) is set, may contain backreferences that will get
-        expanded with the C(regexp) capture groups if the regexp matches.
+      - Required for C(state=present). The line to insert/replace into the file. If C(backrefs) is set, may contain backreferences that will get expanded with the C(regexp) capture groups if the regexp matches.
   backrefs:
     required: false
     default: "no"
     choices: [ "yes", "no" ]
     description:
-      - Used with C(state=present). If set, line can contain backreferences
-        (both positional and named) that will get populated if the C(regexp)
-        matches. This flag changes the operation of the module slightly;
-        C(insertbefore) and C(insertafter) will be ignored, and if the C(regexp)
-        doesn't match anywhere in the file, the file will be left unchanged.
-        If the C(regexp) does match, the last matching line will be replaced by
-        the expanded line parameter.
+      - Used with C(state=present). If set, line can contain backreferences (both positional and named) that will get populated if the C(regexp) matches. This flag changes the operation of the module slightly; C(insertbefore) and C(insertafter) will be ignored, and if the C(regexp) doesn't match anywhere in the file, the file will be left unchanged.
+      - If the C(regexp) does match, the last matching line will be replaced by the expanded line parameter.
   insertafter:
     required: false
     default: EOF
@@ -75,7 +66,6 @@ options:
     choices: [ 'EOF', '*regex*' ]
   insertbefore:
     required: false
-    version_added: "1.1"
     description:
       - Used with C(state=present). If specified, the line will be inserted before the last match of specified regular expression. A value is available; C(BOF) for inserting the line at the beginning of the file.
       - If specified regular expression has no matches, the line will be inserted at the end of the file. May not be used with C(backrefs).
@@ -85,16 +75,13 @@ options:
     choices: [ "yes", "no" ]
     default: "no"
     description:
-      - Used with C(state=present). If specified, the file will be created
-        if it does not already exist. By default it will fail if the file
-        is missing.
+      - Used with C(state=present). If specified, the file will be created if it does not already exist. By default it will fail if the file is missing.
   backup:
     required: false
     default: "no"
     choices: [ "yes", "no" ]
     description:
-      - Create a backup file including the timestamp information so you can
-        get the original file back if you somehow clobbered it incorrectly.
+      - Create a backup file including the timestamp information so you can get the original file back if you somehow clobbered it incorrectly.
   validate:
     required: false
     description:
@@ -105,23 +92,15 @@ options:
     required: false
     default: "auto"
     description:
-      - Specifies the encoding of the source text file to operate on (and thus what the
-        output encoding will be). The default of C(auto) will cause the module to auto-detect 
-        the encoding of the source file and ensure that the modified file is written with the 
-        same encoding.
-        An explicit encoding can be passed as a string that is a valid value to pass to 
-        the .NET framework System.Text.Encoding.GetEncoding() method - see 
-        U(https://msdn.microsoft.com/en-us/library/system.text.encoding%28v=vs.110%29.aspx). 
-        This is mostly useful with C(create=yes) if you want to create a new file with a specific 
-        encoding. If C(create=yes) is specified without a specific encoding, the default encoding 
-        (UTF-8, no BOM) will be used.
+      - Specifies the encoding of the source text file to operate on (and thus what the output encoding will be). The default of C(auto) will cause the module to auto-detect the encoding of the source file and ensure that the modified file is written with the same encoding.
+      - "An explicit encoding can be passed as a string that is a valid value to pass to the .NET framework System.Text.Encoding.GetEncoding() method - see U(https://msdn.microsoft.com/en-us/library/system.text.encoding%28v=vs.110%29.aspx)."
+      - This is mostly useful with C(create=yes) if you want to create a new file with a specific encoding. If C(create=yes) is specified without a specific encoding, the default encoding (UTF-8, no BOM) will be used.
   newline:
     required: false
     description:
       - "Specifies the line separator style to use for the modified file. This defaults to the windows line separator (C(\r\n)). Note that the indicated line separator will be used for file output regardless of the original line separator that appears in the input file."
     choices: [ "windows", "unix" ]
     default: "windows"
-
 """
 
 EXAMPLES = r"""
diff --git a/lib/ansible/modules/windows/win_msi.ps1 b/lib/ansible/modules/windows/win_msi.ps1
index a5b933b569..a3d455beb0 100644
--- a/lib/ansible/modules/windows/win_msi.ps1
+++ b/lib/ansible/modules/windows/win_msi.ps1
@@ -27,13 +27,17 @@ $creates = Get-Attr $params "creates" $false
 $extra_args = Get-Attr $params "extra_args" ""
 $wait = Get-Attr $params "wait" $false | ConvertTo-Bool
 
-If (-not $params.path.GetType)
+$result = New-Object psobject @{
+    changed = $false
+};
+
+If (($creates -ne $false) -and ($state -ne "absent") -and (Test-Path $creates))
 {
-    Fail-Json $result "missing required arguments: path"
+    Exit-Json $result;
 }
 
 $logfile = [IO.Path]::GetTempFileName();
-If ($params.state.GetType -and $params.state -eq "absent")
+if ($state -eq "absent")
 {
   If ($wait)
   {
diff --git a/lib/ansible/modules/windows/win_msi.py b/lib/ansible/modules/windows/win_msi.py
index d365f5bdcf..cfc7e08982 100644
--- a/lib/ansible/modules/windows/win_msi.py
+++ b/lib/ansible/modules/windows/win_msi.py
@@ -61,7 +61,7 @@ options:
             - true
             - false
         default: false
-author: Matt Martz
+author: "Matt Martz (@sivel)"
 '''
 
 EXAMPLES = '''