libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From anthonys...@apache.org
Subject [06/21] libcloud git commit: moved much of drs functionality into the compute driver, last test coded far was stopping drs_preview_failover
Date Wed, 19 Dec 2018 05:34:08 GMT
moved much of drs functionality into the compute driver, last test coded far was stopping drs_preview_failover


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/facbea21
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/facbea21
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/facbea21

Branch: refs/heads/trunk
Commit: facbea218b89487fdff08104532f0c372f4b61d6
Parents: e330274
Author: mitch <mitch.raful@itaas.dimensiondata.com>
Authored: Fri Nov 30 17:47:20 2018 -0500
Committer: mitch <mitch.raful@itaas.dimensiondata.com>
Committed: Fri Nov 30 17:47:20 2018 -0500

----------------------------------------------------------------------
 libcloud/common/nttcis.py                       |   9 +-
 libcloud/compute/drivers/nttcis.py              | 245 +++++++++++++++++++
 .../nttcis/cg_by_src_network_domain.xml         |  51 ++++
 .../fixtures/nttcis/drs_expand_journal.xml      |   6 +
 .../nttcis/drs_snap_shots_by_min_max_time.xml   |  61 +++++
 .../fixtures/nttcis/drs_snapshots_by_min.xml    |  44 ++++
 .../nttcis/drs_start_failover_preview.xml       |   6 +
 .../nttcis/drs_stop_failover_preview.xml        |   6 +
 .../fixtures/nttcis/get_cg_by_name_or_id.xml    |  27 ++
 .../fixtures/nttcis/list_consistency_groups.xml |  51 ++++
 .../fixtures/nttcis/list_drs_snapshots.xml      |  81 ++++++
 libcloud/test/compute/test_nttcis.py            | 166 ++++++++++++-
 12 files changed, 748 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/common/nttcis.py
----------------------------------------------------------------------
diff --git a/libcloud/common/nttcis.py b/libcloud/common/nttcis.py
index faf6650..3232abf 100644
--- a/libcloud/common/nttcis.py
+++ b/libcloud/common/nttcis.py
@@ -17,7 +17,7 @@ NTTCIS Common Components
 """
 import xml.etree.ElementTree as etree
 import re
-import functools
+from functools import wraps, total_ordering
 from copy import deepcopy
 from base64 import b64encode
 from time import sleep
@@ -294,7 +294,7 @@ BAD_MESSAGE_XML_ELEMENTS = (
 
 
 def get_params(func):
-    @functools.wraps(func)
+    @wraps(func)
     def paramed(*args, **kwargs):
         if kwargs:
             for k, v in kwargs.items():
@@ -2054,7 +2054,9 @@ def processor(mapping, name=None):
 
     def process(mapping):
         """
-        This function is recursive, creating attributes for the class factory.
+        This function is recursive, creating attributes for the class factory
+        by taking apart the elements in the  dictionary.  Thus, the calls to
+        handle_seq or handle_map
         :param mapping: the dictionary converted from XML
         :return: itself (recursive)
         """
@@ -2093,6 +2095,7 @@ def processor(mapping, name=None):
     return process(mapping)
 
 
+@total_ordering
 def class_factory(cls_name, attrs):
     """
     This class takes a name and a dictionary to create a class.

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/compute/drivers/nttcis.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/nttcis.py b/libcloud/compute/drivers/nttcis.py
index 8980051..5dca8cd 100644
--- a/libcloud/compute/drivers/nttcis.py
+++ b/libcloud/compute/drivers/nttcis.py
@@ -23,6 +23,7 @@ from libcloud.common.nttcis import LooseVersion
 from libcloud.common.exceptions import BaseHTTPError
 from libcloud.compute.base import NodeDriver, Node, NodeAuthPassword
 from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
+from libcloud.common.nttcis import process_xml, get_params
 from libcloud.common.nttcis import dd_object_to_id
 from libcloud.common.nttcis import NttCisAPIException
 from libcloud.common.nttcis import (NttCisConnection,
@@ -4649,6 +4650,250 @@ class NttCisNodeDriver(NodeDriver):
 
         return new_node
 
+    # DRS methods
+    def create_consistency_group(self, name, journal_size_gb,
+                                 source_server_id, target_server_id,
+                                 description=None):
+        """
+        Create a consistency group
+
+        :param name: Name of consistency group
+        :type name: ``str``
+        :param journal_size_gb: Journal size in GB
+        :type journal_size_gb: ``str``
+        :param source_server_id: Id of the server to copy
+        :type source_server_id: ``str``
+        :param target_server_id: Id of the server to receive the copy
+        :type: ``str``
+        :param description: (Optional) Description of consistency group
+        :type: ``str``
+        :return: :class: `NttCisConsistenccyGroup`
+        """
+
+        consistency_group_elm = ET.Element('createConsistencyGroup',
+                                           {'xmlns': TYPES_URN})
+        ET.SubElement(consistency_group_elm, "name").text = name
+        if description is not None:
+            ET.SubElement(
+                consistency_group_elm, "description").text = description
+        ET.SubElement(
+            consistency_group_elm, "journalSizeGb").text = journal_size_gb
+        server_pair = ET.SubElement(consistency_group_elm, "serverPair")
+        ET.SubElement(
+            server_pair, "sourceServerId").text = source_server_id
+        ET.SubElement(
+            server_pair, "targetServerId").text = target_server_id
+        response = self.connection.request_with_orgId_api_2(
+            "consistencyGroup/createConsistencyGroup",
+            method="POST",
+            data=ET.tostring(consistency_group_elm)).object
+        response_code = findtext(response, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    @get_params
+    def list_consistency_groups(self, params={}):
+        """
+        Functions takes a named parameter that must be one of the following
+        :param params: A dictionary composed of one of the following keys
+        and a value
+        * target_data_center_id=
+        * source_network_domain_id=
+        * target_network_domain_id=
+        * source_server_id=
+        * target_server_id=
+        * name=
+        * state=
+        * operation_status=
+        * drs_infrastructure_status=
+        :return:  `list` of :class: `NttCisConsistencyGroup`
+        """
+
+        response = self.connection.request_with_orgId_api_2(
+            'consistencyGroup/consistencyGroup', params=params).object
+        cgs = self._to_consistency_groups(response)
+        return cgs
+
+    def get_consistency_group(self, consistency_group_id):
+        """
+        Retrieves a Consistency by it's id and is more efficient thatn listing
+        all consistency groups and filtering that result.
+        :param consistency_group_id: An id of a consistency group
+        :type consistency_group_id: ``str``
+        :return: :class: `NttCisConsistencygroup`
+        """
+        response = self.connection.request_with_orgId_api_2(
+            "consistencyGroup/consistencyGroup/%s" % consistency_group_id
+        ).object
+        cg = self._to_process(response)
+        return cg
+
+    def list_consistency_group_snapshots(self, consistency_group_id,
+                                         create_time_min=None,
+                                         create_time_max=None):
+        """
+        Optional parameters identify the date of creation of Consistency Group
+        snapshots in *XML Schema (XSD) date time format. Best used as a
+        combination of createTime.MIN and createTime.MAX. If neither is
+        provided then all snapshots up to the possible maximum of 1014
+        will be returned. If MIN is provided by itself, all snapshots
+        between the time specified by MIN and the point in time of
+        execution will be returned. If MAX is provided by itself,
+        then all snapshots up to that point in time (up to the
+        maximum number of 1014) will be returned. MIN and MAX are
+        inclusive for this API function
+
+        :param consistency_group_id: The id of consistency group
+        :type consistency_group_id: ``str``
+        :param create_time_min: (Optional) in form YYYY-MM-DDT00:00.00.00Z or
+                                           substitute time offset for Z, i.e,
+                                           -05:00
+        :type create_time_min: ``str``
+        :param create_time_max: (Optional) in form YYYY-MM-DDT00:00:00.000Z or
+                                           substitute time offset for Z, i.e,
+                                           -05:00
+        :type create_time_max: ``str``
+        :return: `list` of :class" `NttCisSnapshots`
+        """
+
+        if create_time_min is None and create_time_max is None:
+            params = {"consistencyGroupId": consistency_group_id}
+        elif create_time_min and create_time_max:
+            params = {"consistencyGroupId": consistency_group_id,
+                      "createTime.MIN": create_time_min,
+                      "createTime.MAX": create_time_max
+                      }
+        elif create_time_min or create_time_max:
+            if create_time_max is not None:
+                params = {"consistencyGroupId": consistency_group_id,
+                          "createTime.MAX": create_time_max
+                          }
+            elif create_time_min is not None:
+                params = {"consistencyGroupId": consistency_group_id,
+                          "createTime.MIN": create_time_min
+                          }
+        paged_result = self.connection.request_with_orgId_api_2(
+            'consistencyGroup/snapshot',
+            method='GET',
+            params=params
+        ).object
+        snapshots = self._to_process(paged_result)
+        return snapshots
+
+    def expand_journal(self, consistency_group_id, size_gb):
+        """
+        Expand the consistency group's journhal size in 100Gb increments
+        :param consistency_group_id: The consistency group's UUID
+        :type consistency_group_id: ``str``
+        :param size_gb: Gb in 100 Gb increments
+        :type size_gb: ``str``
+        :return: ``bool``
+        """
+
+        expand_elm = ET.Element("expandJournal", {"id": consistency_group_id,
+                                                  "xmlns": TYPES_URN})
+        ET.SubElement(expand_elm, "sizeGb").text = size_gb
+        response = self.connection.request_with_orgId_api_2(
+            "consistencyGroup/expandJournal",
+            method="POST",
+            data=ET.tostring(expand_elm)).object
+        response_code = findtext(response, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def start_drs_failover_preview(self, consistency_group_id, snapshot_id):
+        """
+        Brings a Consistency Group into PREVIEWING_SNAPSHOT mode
+
+        :param consistency_group_id: Id of the Consistency Group to put into
+                                     PRIEVEW_MODE
+        :type consistency_group_id: ``str``
+        :param snapshot_id: Id of the Snapshot to preview
+        :type snapshot_id: ``str``
+        :return: True/False
+        :rtype: ``bool``
+        """
+        preview_elm = ET.Element("startPreviewSnapshot",
+                                 {"consistencyGroupId": consistency_group_id,
+                                  "xmlns": TYPES_URN
+                                  })
+        ET.SubElement(preview_elm, "snapshotId").text = snapshot_id
+        response = self.connection.request_with_orgId_api_2(
+            "consistencyGroup/startPreviewSnapshot",
+            method="POST",
+            data=ET.tostring(preview_elm)).object
+        response_code = findtext(response, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def stop_drs_failover_preview(self, consistency_group_id):
+        """
+        Takes a Consistency Group out of PREVIEW_MODE and back to DRS_MODE
+
+        :param consistency_group_id: Consistency Group's Id
+        :type ``str``
+        :return: True/False
+        :rtype: ``bool``
+        """
+        preview_elm = ET.Element("stopPreviewSnapshot",
+                                 {"consistencyGroupId": consistency_group_id,
+                                  "xmlns": TYPES_URN})
+        response = self.connection.request_with_orgId_api_2(
+            "consistencyGroup/stopPreviewSnapshot",
+            method="POST",
+            data=ET.tostring(preview_elm)).object
+        response_code = findtext(response, 'responseCode', TYPES_URN)
+        return response_code in ['IN_PROGRESS', 'OK']
+
+    def initiate_drs_failover(self, consistency_group_id):
+        """
+        This method is irreversible.
+        It will failover the Consistency Group while removing it as well.
+
+        :param consistency_group_id: Consistency Group's Id to failover
+        :type consistency_group_id: ``str``
+        :return: True/False
+        :rtype: ``bool``
+        """
+        failover_elm = ET.Element("initiateFailover",
+                                  {"consistencyGroupId": consistency_group_id,
+                                   "xmlns": TYPES_URN})
+        response = self.connection.request_with_orgId_api_2(
+            "consistencyGroup/initiateFailover",
+            method="POST",
+            data=ET.tostring(failover_elm)).object
+        response_code = findtext(response, "responseCode", TYPES_URN)
+        return response_code in ["IN_PROGRESS", "OK"]
+
+    def delete_consistency_group(self, consistency_group_id):
+        """
+        Delete's a Consistency Group
+
+        :param consistency_group_id: Id of Consistency Group to delete
+        :type ``str``
+        :return: True/False
+        :rtype: ``bool``
+        """
+        delete_elm = ET.Element("deleteConsistencyGroup",
+                                {"id": consistency_group_id,
+                                 "xmlns": TYPES_URN})
+        response = self.connection.request_with_orgId_api_2(
+            "consistencyGroup/deleteConsistencyGroup",
+            method="POST",
+            data=ET.tostring(delete_elm)).object
+        response_code = findtext(response, "responseCode", TYPES_URN)
+        return response_code in ["IN_PROGRESS", "OK"]
+
+    def _to_consistency_groups(self, object):
+        cgs = findall(object, 'consistencyGroup', TYPES_URN)
+        return [self._to_process(el) for el in cgs]
+
+    def _to_drs_snapshots(self, object):
+        snapshots = []
+        for element in object.findall(fixxpath("snapshot", TYPES_URN)):
+            snapshots.append(self._to_process(element))
+        return snapshots
+
+    def _to_process(self, element):
+        return process_xml(ET.tostring(element))
+
     def _format_csv(self, http_response):
         text = http_response.read()
         lines = str.splitlines(ensure_string(text))

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/cg_by_src_network_domain.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/cg_by_src_network_domain.xml b/libcloud/test/compute/fixtures/nttcis/cg_by_src_network_domain.xml
new file mode 100644
index 0000000..3594cbb
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/cg_by_src_network_domain.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<consistencyGroups xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="2" totalCount="2" pageSize="250">
+    <consistencyGroup id="195a426b-4559-4c79-849e-f22cdf2bfb6e">
+        <name>sdk_test2_cg</name>
+        <description>A test consistency group</description>
+        <journal sizeGb="100" extentCount="1"/>
+        <source datacenterId="NADRAASLAB01" networkDomainId="f9d6a249-c922-4fa1-9f0f-de5b452c4026">
+            <networkDomainName>DRS-ProdEng-East-ND1</networkDomainName>
+        </source>
+        <target datacenterId="NADRAASLAB02" networkDomainId="e46c8815-193f-402d-b8a5-682eaa646fb2">
+            <networkDomainName>DRS-ProdEng-West-ND1</networkDomainName>
+        </target>
+        <serverPair id="55416e8c-d198-4d33-a7f9-df7f30b8813b" state="NORMAL">
+            <sourceServer id="032f3967-00e4-4780-b4ef-8587460f9dd4" primaryNicIpv4="192.168.12.8" primaryNicIpv6="2607:f480:111:1426:3dc9:25dc:4985:81b2">
+                <name>src-sdk-test</name>
+            </sourceServer>
+            <targetServer id="aee58575-38e2-495f-89d3-854e6a886411" primaryNicIpv4="192.168.22.7" primaryNicIpv6="2607:f480:211:1159:2dff:40ed:ee7c:4738">
+                <name>tgt-sdk-test</name>
+            </targetServer>
+        </serverPair>
+        <createTime>2018-11-12T20:53:10.000Z</createTime>
+        <operationStatus>DRS_MODE</operationStatus>
+        <drsInfrastructure enabled="true" status="ACTIVE" updateTime="2018-11-29T17:40:02.000Z"/>
+        <drsStatusCheckFailureCount>0</drsStatusCheckFailureCount>
+        <state>NORMAL</state>
+    </consistencyGroup>
+    <consistencyGroup id="90fc8db6-0207-443d-9c2c-04b19eb9fd6b">
+        <name>CG-Re-IP-Scenario-2</name>
+        <description>CG-Re-IP-Scenario-2</description>
+        <journal sizeGb="100" extentCount="1"/>
+        <source datacenterId="NADRAASLAB01" networkDomainId="f9d6a249-c922-4fa1-9f0f-de5b452c4026">
+            <networkDomainName>DRS-ProdEng-East-ND1</networkDomainName>
+        </source>
+        <target datacenterId="NADRAASLAB02" networkDomainId="e46c8815-193f-402d-b8a5-682eaa646fb2">
+            <networkDomainName>DRS-ProdEng-West-ND1</networkDomainName>
+        </target>
+        <serverPair id="a041f587-982e-49dc-9db8-1b987a0ee7b6" state="NORMAL">
+            <sourceServer id="6a15da8a-ea2c-4938-bca4-2c5e66355c8c" primaryNicIpv4="192.168.12.6" primaryNicIpv6="2607:f480:111:1426:87:6706:e811:f182">
+                <name>Src-Re-IP-RHEL7</name>
+            </sourceServer>
+            <targetServer id="f55aef9f-ed6f-40bd-a00d-33fb184d5838" primaryNicIpv4="192.168.22.6" primaryNicIpv6="2607:f480:211:1159:76b:dce4:a3f6:ad8b">
+                <name>Tgt-Re-IP-RHEL7</name>
+            </targetServer>
+        </serverPair>
+        <createTime>2018-11-16T15:41:48.000Z</createTime>
+        <operationStatus>DRS_MODE</operationStatus>
+        <drsInfrastructure enabled="true" status="ACTIVE" updateTime="2018-11-29T17:40:02.000Z"/>
+        <drsStatusCheckFailureCount>0</drsStatusCheckFailureCount>
+        <state>NORMAL</state>
+    </consistencyGroup>
+</consistencyGroups>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/drs_expand_journal.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/drs_expand_journal.xml b/libcloud/test/compute/fixtures/nttcis/drs_expand_journal.xml
new file mode 100644
index 0000000..032f2ff
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/drs_expand_journal.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="na_20181130T161652068-0500_fff53b78-2dc0-4728-b695-6ad4bb4a8b70">
+    <operation>EXPAND_JOURNAL</operation>
+    <responseCode>IN_PROGRESS</responseCode>
+    <message>Request to Expand DRS Journal Space has been accepted. Please use appropriate Get or List API for status.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/drs_snap_shots_by_min_max_time.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/drs_snap_shots_by_min_max_time.xml b/libcloud/test/compute/fixtures/nttcis/drs_snap_shots_by_min_max_time.xml
new file mode 100644
index 0000000..a05202d
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/drs_snap_shots_by_min_max_time.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<consistencyGroupSnapshots xmlns="urn:didata.com:api:cloud:types" totalCount="58" journalUsageGb="0.34" protectionWindow="P0Y0M16DT23H4M34.604S" predictedProtectionWindow="P26Y2M0DT19H47M12.223S">
+    <snapshot id="2304625" createTime="2018-11-28T18:52:59.396-05:00" sizeKb="108"/>
+    <snapshot id="2302065" createTime="2018-11-28T18:27:00.846-05:00" sizeKb="230"/>
+    <snapshot id="2299476" createTime="2018-11-28T18:01:00.974-05:00" sizeKb="108"/>
+    <snapshot id="2296916" createTime="2018-11-28T17:35:01.362-05:00" sizeKb="343"/>
+    <snapshot id="2294318" createTime="2018-11-28T17:09:01.650-05:00" sizeKb="235"/>
+    <snapshot id="2291728" createTime="2018-11-28T16:43:02.315-05:00" sizeKb="108"/>
+    <snapshot id="2289168" createTime="2018-11-28T16:17:02.322-05:00" sizeKb="214"/>
+    <snapshot id="2286587" createTime="2018-11-28T15:51:02.819-05:00" sizeKb="108"/>
+    <snapshot id="2284027" createTime="2018-11-28T15:25:02.998-05:00" sizeKb="167"/>
+    <snapshot id="2281452" createTime="2018-11-28T14:59:02.734-05:00" sizeKb="111"/>
+    <snapshot id="2278888" createTime="2018-11-28T14:33:03.398-05:00" sizeKb="105"/>
+    <snapshot id="2277599" createTime="2018-11-28T14:20:03.124-05:00" sizeKb="1142"/>
+    <snapshot id="2276214" createTime="2018-11-28T14:07:02.998-05:00" sizeKb="211"/>
+    <snapshot id="2273629" createTime="2018-11-28T13:41:03.464-05:00" sizeKb="108"/>
+    <snapshot id="2271069" createTime="2018-11-28T13:15:03.119-05:00" sizeKb="200"/>
+    <snapshot id="2268490" createTime="2018-11-28T12:49:05.695-05:00" sizeKb="108"/>
+    <snapshot id="2265930" createTime="2018-11-28T12:23:06.184-05:00" sizeKb="264"/>
+    <snapshot id="2263333" createTime="2018-11-28T11:57:06.200-05:00" sizeKb="108"/>
+    <snapshot id="2260773" createTime="2018-11-28T11:31:07.442-05:00" sizeKb="108"/>
+    <snapshot id="2258213" createTime="2018-11-28T11:05:07.440-05:00" sizeKb="641"/>
+    <snapshot id="2255583" createTime="2018-11-28T10:39:09.091-05:00" sizeKb="168"/>
+    <snapshot id="2253005" createTime="2018-11-28T10:13:08.800-05:00" sizeKb="263"/>
+    <snapshot id="2250405" createTime="2018-11-28T09:47:08.754-05:00" sizeKb="108"/>
+    <snapshot id="2247845" createTime="2018-11-28T09:21:09.153-05:00" sizeKb="205"/>
+    <snapshot id="2245264" createTime="2018-11-28T08:55:09.099-05:00" sizeKb="108"/>
+    <snapshot id="2242704" createTime="2018-11-28T08:29:08.941-05:00" sizeKb="134"/>
+    <snapshot id="2240132" createTime="2018-11-28T08:03:09.231-05:00" sizeKb="200"/>
+    <snapshot id="2237556" createTime="2018-11-28T07:37:09.816-05:00" sizeKb="108"/>
+    <snapshot id="2234996" createTime="2018-11-28T07:11:09.962-05:00" sizeKb="200"/>
+    <snapshot id="2232417" createTime="2018-11-28T06:45:10.052-05:00" sizeKb="108"/>
+    <snapshot id="2229857" createTime="2018-11-28T06:19:09.896-05:00" sizeKb="209"/>
+    <snapshot id="2227273" createTime="2018-11-28T05:53:11.393-05:00" sizeKb="108"/>
+    <snapshot id="2224713" createTime="2018-11-28T05:27:11.856-05:00" sizeKb="229"/>
+    <snapshot id="2222126" createTime="2018-11-28T05:01:11.882-05:00" sizeKb="108"/>
+    <snapshot id="2219566" createTime="2018-11-28T04:35:13.909-05:00" sizeKb="108"/>
+    <snapshot id="2217006" createTime="2018-11-28T04:09:14.609-05:00" sizeKb="278"/>
+    <snapshot id="2214414" createTime="2018-11-28T03:43:15.124-05:00" sizeKb="54"/>
+    <snapshot id="2213134" createTime="2018-11-28T03:30:15.088-05:00" sizeKb="1565"/>
+    <snapshot id="2211652" createTime="2018-11-28T03:17:16.051-05:00" sizeKb="235"/>
+    <snapshot id="2209063" createTime="2018-11-28T02:51:16.629-05:00" sizeKb="108"/>
+    <snapshot id="2206503" createTime="2018-11-28T02:25:17.032-05:00" sizeKb="269"/>
+    <snapshot id="2203908" createTime="2018-11-28T01:59:18.396-05:00" sizeKb="108"/>
+    <snapshot id="2201348" createTime="2018-11-28T01:33:18.414-05:00" sizeKb="108"/>
+    <snapshot id="2198788" createTime="2018-11-28T01:07:18.547-05:00" sizeKb="235"/>
+    <snapshot id="2196199" createTime="2018-11-28T00:41:19.622-05:00" sizeKb="108"/>
+    <snapshot id="2193639" createTime="2018-11-28T00:15:20.066-05:00" sizeKb="223"/>
+    <snapshot id="2191056" createTime="2018-11-27T23:49:20.018-05:00" sizeKb="108"/>
+    <snapshot id="2188496" createTime="2018-11-27T23:23:20.103-05:00" sizeKb="200"/>
+    <snapshot id="2185917" createTime="2018-11-27T22:57:20.219-05:00" sizeKb="108"/>
+    <snapshot id="2183357" createTime="2018-11-27T22:31:20.558-05:00" sizeKb="132"/>
+    <snapshot id="2180786" createTime="2018-11-27T22:05:20.347-05:00" sizeKb="185"/>
+    <snapshot id="2178205" createTime="2018-11-27T21:39:20.101-05:00" sizeKb="108"/>
+    <snapshot id="2175645" createTime="2018-11-27T21:13:20.264-05:00" sizeKb="200"/>
+    <snapshot id="2173066" createTime="2018-11-27T20:47:21.296-05:00" sizeKb="108"/>
+    <snapshot id="2170506" createTime="2018-11-27T20:21:21.810-05:00" sizeKb="245"/>
+    <snapshot id="2167911" createTime="2018-11-27T19:55:21.447-05:00" sizeKb="117"/>
+    <snapshot id="2165349" createTime="2018-11-27T19:29:21.402-05:00" sizeKb="132"/>
+    <snapshot id="2162778" createTime="2018-11-27T19:03:22.026-05:00" sizeKb="203"/>
+</consistencyGroupSnapshots>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/drs_snapshots_by_min.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/drs_snapshots_by_min.xml b/libcloud/test/compute/fixtures/nttcis/drs_snapshots_by_min.xml
new file mode 100644
index 0000000..c5ecc1a
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/drs_snapshots_by_min.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<consistencyGroupSnapshots xmlns="urn:didata.com:api:cloud:types" totalCount="41" journalUsageGb="0.34" protectionWindow="P0Y0M16DT23H38M14.357S" predictedProtectionWindow="P12Y5M5DT12H44M26.435S">
+    <snapshot id="2428274" createTime="2018-11-29T15:37:55.224-05:00" sizeKb="0"/>
+    <snapshot id="2428269" createTime="2018-11-29T15:37:52.175-05:00" sizeKb="96"/>
+    <snapshot id="2425994" createTime="2018-11-29T15:14:45.974-05:00" sizeKb="143"/>
+    <snapshot id="2423403" createTime="2018-11-29T14:48:46.206-05:00" sizeKb="108"/>
+    <snapshot id="2420843" createTime="2018-11-29T14:22:46.196-05:00" sizeKb="55"/>
+    <snapshot id="2419559" createTime="2018-11-29T14:09:46.517-05:00" sizeKb="295"/>
+    <snapshot id="2418156" createTime="2018-11-29T13:56:46.893-05:00" sizeKb="88"/>
+    <snapshot id="2416076" createTime="2018-11-29T13:35:39.890-05:00" sizeKb="20"/>
+    <snapshot id="2415596" createTime="2018-11-29T13:30:47.327-05:00" sizeKb="146"/>
+    <snapshot id="2413027" createTime="2018-11-29T13:04:47.542-05:00" sizeKb="214"/>
+    <snapshot id="2410444" createTime="2018-11-29T12:38:47.674-05:00" sizeKb="108"/>
+    <snapshot id="2407884" createTime="2018-11-29T12:12:47.920-05:00" sizeKb="200"/>
+    <snapshot id="2405305" createTime="2018-11-29T11:46:47.660-05:00" sizeKb="108"/>
+    <snapshot id="2402745" createTime="2018-11-29T11:20:48.156-05:00" sizeKb="655"/>
+    <snapshot id="2400112" createTime="2018-11-29T10:54:48.439-05:00" sizeKb="143"/>
+    <snapshot id="2397537" createTime="2018-11-29T10:28:49.248-05:00" sizeKb="171"/>
+    <snapshot id="2394955" createTime="2018-11-29T10:02:49.803-05:00" sizeKb="196"/>
+    <snapshot id="2392380" createTime="2018-11-29T09:36:49.330-05:00" sizeKb="108"/>
+    <snapshot id="2389820" createTime="2018-11-29T09:10:48.981-05:00" sizeKb="219"/>
+    <snapshot id="2387237" createTime="2018-11-29T08:44:48.757-05:00" sizeKb="108"/>
+    <snapshot id="2384677" createTime="2018-11-29T08:18:48.842-05:00" sizeKb="226"/>
+    <snapshot id="2382089" createTime="2018-11-29T07:52:49.407-05:00" sizeKb="108"/>
+    <snapshot id="2379529" createTime="2018-11-29T07:26:49.154-05:00" sizeKb="200"/>
+    <snapshot id="2376950" createTime="2018-11-29T07:00:49.669-05:00" sizeKb="108"/>
+    <snapshot id="2374390" createTime="2018-11-29T06:34:50.271-05:00" sizeKb="130"/>
+    <snapshot id="2371821" createTime="2018-11-29T06:08:50.573-05:00" sizeKb="240"/>
+    <snapshot id="2369231" createTime="2018-11-29T05:42:50.281-05:00" sizeKb="108"/>
+    <snapshot id="2366671" createTime="2018-11-29T05:16:51.055-05:00" sizeKb="151"/>
+    <snapshot id="2364099" createTime="2018-11-29T04:50:52.032-05:00" sizeKb="108"/>
+    <snapshot id="2361539" createTime="2018-11-29T04:24:52.037-05:00" sizeKb="235"/>
+    <snapshot id="2358950" createTime="2018-11-29T03:58:51.637-05:00" sizeKb="54"/>
+    <snapshot id="2357670" createTime="2018-11-29T03:45:51.760-05:00" sizeKb="2808"/>
+    <snapshot id="2356056" createTime="2018-11-29T03:32:51.657-05:00" sizeKb="108"/>
+    <snapshot id="2353496" createTime="2018-11-29T03:06:51.467-05:00" sizeKb="195"/>
+    <snapshot id="2350920" createTime="2018-11-29T02:40:51.090-05:00" sizeKb="108"/>
+    <snapshot id="2348360" createTime="2018-11-29T02:14:51.780-05:00" sizeKb="264"/>
+    <snapshot id="2345769" createTime="2018-11-29T01:48:52.282-05:00" sizeKb="108"/>
+    <snapshot id="2343209" createTime="2018-11-29T01:22:52.766-05:00" sizeKb="222"/>
+    <snapshot id="2340624" createTime="2018-11-29T00:56:53.151-05:00" sizeKb="108"/>
+    <snapshot id="2338064" createTime="2018-11-29T00:30:53.068-05:00" sizeKb="108"/>
+    <snapshot id="2335504" createTime="2018-11-29T00:04:53.181-05:00" sizeKb="213"/>
+</consistencyGroupSnapshots>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/drs_start_failover_preview.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/drs_start_failover_preview.xml b/libcloud/test/compute/fixtures/nttcis/drs_start_failover_preview.xml
new file mode 100644
index 0000000..353c223
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/drs_start_failover_preview.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="na_20181130T170150308-0500_cff36582-f930-4cd5-8909-17f447060707">
+    <operation>START_PREVIEW_SNAPSHOT</operation>
+    <responseCode>IN_PROGRESS</responseCode>
+    <message>Request to Start Preview Snapshot has been accepted. Please use appropriate Get or List API for status.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/drs_stop_failover_preview.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/drs_stop_failover_preview.xml b/libcloud/test/compute/fixtures/nttcis/drs_stop_failover_preview.xml
new file mode 100644
index 0000000..386b601
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/drs_stop_failover_preview.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="na_20181130T174221630-0500_91b9b2e4-5a9b-43be-aad2-4df7f58045ab">
+    <operation>STOP_PREVIEW_SNAPSHOT</operation>
+    <responseCode>IN_PROGRESS</responseCode>
+    <message>Request to Stop Preview Snapshot has been accepted. Please use appropriate Get or List API for status.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/get_cg_by_name_or_id.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/get_cg_by_name_or_id.xml b/libcloud/test/compute/fixtures/nttcis/get_cg_by_name_or_id.xml
new file mode 100644
index 0000000..9b594d5
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/get_cg_by_name_or_id.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<consistencyGroups xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="1" totalCount="1" pageSize="250">
+    <consistencyGroup id="195a426b-4559-4c79-849e-f22cdf2bfb6e">
+        <name>sdk_test2_cg</name>
+        <description>A test consistency group</description>
+        <journal sizeGb="100" extentCount="1"/>
+        <source datacenterId="NADRAASLAB01" networkDomainId="f9d6a249-c922-4fa1-9f0f-de5b452c4026">
+            <networkDomainName>DRS-ProdEng-East-ND1</networkDomainName>
+        </source>
+        <target datacenterId="NADRAASLAB02" networkDomainId="e46c8815-193f-402d-b8a5-682eaa646fb2">
+            <networkDomainName>DRS-ProdEng-West-ND1</networkDomainName>
+        </target>
+        <serverPair id="55416e8c-d198-4d33-a7f9-df7f30b8813b" state="NORMAL">
+            <sourceServer id="032f3967-00e4-4780-b4ef-8587460f9dd4" primaryNicIpv4="192.168.12.8" primaryNicIpv6="2607:f480:111:1426:3dc9:25dc:4985:81b2">
+                <name>src-sdk-test</name>
+            </sourceServer>
+            <targetServer id="aee58575-38e2-495f-89d3-854e6a886411" primaryNicIpv4="192.168.22.7" primaryNicIpv6="2607:f480:211:1159:2dff:40ed:ee7c:4738">
+                <name>tgt-sdk-test</name>
+            </targetServer>
+        </serverPair>
+        <createTime>2018-11-12T20:53:10.000Z</createTime>
+        <operationStatus>DRS_MODE</operationStatus>
+        <drsInfrastructure enabled="true" status="ACTIVE" updateTime="2018-11-29T17:55:02.000Z"/>
+        <drsStatusCheckFailureCount>0</drsStatusCheckFailureCount>
+        <state>NORMAL</state>
+    </consistencyGroup>
+</consistencyGroups>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/list_consistency_groups.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/list_consistency_groups.xml b/libcloud/test/compute/fixtures/nttcis/list_consistency_groups.xml
new file mode 100644
index 0000000..1ebc5b1
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/list_consistency_groups.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<consistencyGroups xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="2" totalCount="2" pageSize="250">
+    <consistencyGroup id="195a426b-4559-4c79-849e-f22cdf2bfb6e">
+        <name>sdk_test2_cg</name>
+        <description>A test consistency group</description>
+        <journal sizeGb="100" extentCount="1"/>
+        <source datacenterId="NADRAASLAB01" networkDomainId="f9d6a249-c922-4fa1-9f0f-de5b452c4026">
+            <networkDomainName>DRS-ProdEng-East-ND1</networkDomainName>
+        </source>
+        <target datacenterId="NADRAASLAB02" networkDomainId="e46c8815-193f-402d-b8a5-682eaa646fb2">
+            <networkDomainName>DRS-ProdEng-West-ND1</networkDomainName>
+        </target>
+        <serverPair id="55416e8c-d198-4d33-a7f9-df7f30b8813b" state="NORMAL">
+            <sourceServer id="032f3967-00e4-4780-b4ef-8587460f9dd4" primaryNicIpv4="192.168.12.8" primaryNicIpv6="2607:f480:111:1426:3dc9:25dc:4985:81b2">
+                <name>src-sdk-test</name>
+            </sourceServer>
+            <targetServer id="aee58575-38e2-495f-89d3-854e6a886411" primaryNicIpv4="192.168.22.7" primaryNicIpv6="2607:f480:211:1159:2dff:40ed:ee7c:4738">
+                <name>tgt-sdk-test</name>
+            </targetServer>
+        </serverPair>
+        <createTime>2018-11-12T20:53:10.000Z</createTime>
+        <operationStatus>DRS_MODE</operationStatus>
+        <drsInfrastructure enabled="true" status="ACTIVE" updateTime="2018-11-29T17:25:02.000Z"/>
+        <drsStatusCheckFailureCount>0</drsStatusCheckFailureCount>
+        <state>NORMAL</state>
+    </consistencyGroup>
+    <consistencyGroup id="90fc8db6-0207-443d-9c2c-04b19eb9fd6b">
+        <name>CG-Re-IP-Scenario-2</name>
+        <description>CG-Re-IP-Scenario-2</description>
+        <journal sizeGb="100" extentCount="1"/>
+        <source datacenterId="NADRAASLAB01" networkDomainId="f9d6a249-c922-4fa1-9f0f-de5b452c4026">
+            <networkDomainName>DRS-ProdEng-East-ND1</networkDomainName>
+        </source>
+        <target datacenterId="NADRAASLAB02" networkDomainId="e46c8815-193f-402d-b8a5-682eaa646fb2">
+            <networkDomainName>DRS-ProdEng-West-ND1</networkDomainName>
+        </target>
+        <serverPair id="a041f587-982e-49dc-9db8-1b987a0ee7b6" state="NORMAL">
+            <sourceServer id="6a15da8a-ea2c-4938-bca4-2c5e66355c8c" primaryNicIpv4="192.168.12.6" primaryNicIpv6="2607:f480:111:1426:87:6706:e811:f182">
+                <name>Src-Re-IP-RHEL7</name>
+            </sourceServer>
+            <targetServer id="f55aef9f-ed6f-40bd-a00d-33fb184d5838" primaryNicIpv4="192.168.22.6" primaryNicIpv6="2607:f480:211:1159:76b:dce4:a3f6:ad8b">
+                <name>Tgt-Re-IP-RHEL7</name>
+            </targetServer>
+        </serverPair>
+        <createTime>2018-11-16T15:41:48.000Z</createTime>
+        <operationStatus>DRS_MODE</operationStatus>
+        <drsInfrastructure enabled="true" status="ACTIVE" updateTime="2018-11-29T17:25:02.000Z"/>
+        <drsStatusCheckFailureCount>0</drsStatusCheckFailureCount>
+        <state>NORMAL</state>
+    </consistencyGroup>
+</consistencyGroups>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/fixtures/nttcis/list_drs_snapshots.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/nttcis/list_drs_snapshots.xml b/libcloud/test/compute/fixtures/nttcis/list_drs_snapshots.xml
new file mode 100644
index 0000000..d149b98
--- /dev/null
+++ b/libcloud/test/compute/fixtures/nttcis/list_drs_snapshots.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<consistencyGroupSnapshots xmlns="urn:didata.com:api:cloud:types" totalCount="1014" journalUsageGb="0.34" protectionWindow="P0Y0M16DT21H40M23.820S" predictedProtectionWindow="P13Y4M12DT8H43M55.927S">
+    <snapshot id="2416511" createTime="2018-11-29T13:40:04.687-05:00" sizeKb="0"/>
+    <snapshot id="2416506" createTime="2018-11-29T13:40:01.645-05:00" sizeKb="18"/>
+    <snapshot id="2416076" createTime="2018-11-29T13:35:39.890-05:00" sizeKb="20"/>
+    <snapshot id="2415596" createTime="2018-11-29T13:30:47.327-05:00" sizeKb="146"/>
+    <snapshot id="2413027" createTime="2018-11-29T13:04:47.542-05:00" sizeKb="214"/>
+    <snapshot id="2410444" createTime="2018-11-29T12:38:47.674-05:00" sizeKb="108"/>
+    <snapshot id="2407884" createTime="2018-11-29T12:12:47.920-05:00" sizeKb="200"/>
+    <snapshot id="2405305" createTime="2018-11-29T11:46:47.660-05:00" sizeKb="108"/>
+    <snapshot id="2402745" createTime="2018-11-29T11:20:48.156-05:00" sizeKb="57"/>
+    <snapshot id="2401461" createTime="2018-11-29T11:07:48.186-05:00" sizeKb="597"/>
+    <snapshot id="2400112" createTime="2018-11-29T10:54:48.439-05:00" sizeKb="143"/>
+    <snapshot id="2397537" createTime="2018-11-29T10:28:49.248-05:00" sizeKb="171"/>
+    <snapshot id="2394955" createTime="2018-11-29T10:02:49.803-05:00" sizeKb="196"/>
+    <snapshot id="2392380" createTime="2018-11-29T09:36:49.330-05:00" sizeKb="108"/>
+    <snapshot id="2389820" createTime="2018-11-29T09:10:48.981-05:00" sizeKb="219"/>
+    <snapshot id="2387237" createTime="2018-11-29T08:44:48.757-05:00" sizeKb="108"/>
+    <snapshot id="2384677" createTime="2018-11-29T08:18:48.842-05:00" sizeKb="226"/>
+    <snapshot id="2382089" createTime="2018-11-29T07:52:49.407-05:00" sizeKb="108"/>
+    <snapshot id="2379529" createTime="2018-11-29T07:26:49.154-05:00" sizeKb="200"/>
+    <snapshot id="2376950" createTime="2018-11-29T07:00:49.669-05:00" sizeKb="108"/>
+    <snapshot id="2374390" createTime="2018-11-29T06:34:50.271-05:00" sizeKb="130"/>
+    <snapshot id="2371821" createTime="2018-11-29T06:08:50.573-05:00" sizeKb="240"/>
+    <snapshot id="2369231" createTime="2018-11-29T05:42:50.281-05:00" sizeKb="108"/>
+    <snapshot id="2366671" createTime="2018-11-29T05:16:51.055-05:00" sizeKb="151"/>
+    <snapshot id="2364099" createTime="2018-11-29T04:50:52.032-05:00" sizeKb="108"/>
+    <snapshot id="2361539" createTime="2018-11-29T04:24:52.037-05:00" sizeKb="235"/>
+    <snapshot id="2358950" createTime="2018-11-29T03:58:51.637-05:00" sizeKb="54"/>
+    <snapshot id="2357670" createTime="2018-11-29T03:45:51.760-05:00" sizeKb="2808"/>
+    <snapshot id="2356056" createTime="2018-11-29T03:32:51.657-05:00" sizeKb="108"/>
+    <snapshot id="2353496" createTime="2018-11-29T03:06:51.467-05:00" sizeKb="195"/>
+    <snapshot id="2350920" createTime="2018-11-29T02:40:51.090-05:00" sizeKb="108"/>
+    <snapshot id="2348360" createTime="2018-11-29T02:14:51.780-05:00" sizeKb="264"/>
+    <snapshot id="2345769" createTime="2018-11-29T01:48:52.282-05:00" sizeKb="108"/>
+    <snapshot id="2343209" createTime="2018-11-29T01:22:52.766-05:00" sizeKb="222"/>
+    <snapshot id="2340624" createTime="2018-11-29T00:56:53.151-05:00" sizeKb="108"/>
+    <snapshot id="2338064" createTime="2018-11-29T00:30:53.068-05:00" sizeKb="108"/>
+    <snapshot id="2335504" createTime="2018-11-29T00:04:53.181-05:00" sizeKb="213"/>
+    <snapshot id="2332925" createTime="2018-11-28T23:38:53.648-05:00" sizeKb="108"/>
+    <snapshot id="2330365" createTime="2018-11-28T23:12:54.848-05:00" sizeKb="219"/>
+    <snapshot id="2327779" createTime="2018-11-28T22:46:55.800-05:00" sizeKb="121"/>
+    <snapshot id="2325213" createTime="2018-11-28T22:20:55.562-05:00" sizeKb="208"/>
+    <snapshot id="2322630" createTime="2018-11-28T21:54:56.854-05:00" sizeKb="108"/>
+    <snapshot id="2320070" createTime="2018-11-28T21:28:57.084-05:00" sizeKb="134"/>
+    <snapshot id="2317498" createTime="2018-11-28T21:02:57.166-05:00" sizeKb="200"/>
+    <snapshot id="2314922" createTime="2018-11-28T20:36:57.524-05:00" sizeKb="108"/>
+    <snapshot id="2312362" createTime="2018-11-28T20:10:59.006-05:00" sizeKb="200"/>
+    <snapshot id="2309783" createTime="2018-11-28T19:44:59.463-05:00" sizeKb="108"/>
+    <snapshot id="2307223" createTime="2018-11-28T19:18:59.395-05:00" sizeKb="261"/>
+    <snapshot id="2304625" createTime="2018-11-28T18:52:59.396-05:00" sizeKb="108"/>
+    <snapshot id="2302065" createTime="2018-11-28T18:27:00.846-05:00" sizeKb="230"/>
+    <snapshot id="2299476" createTime="2018-11-28T18:01:00.974-05:00" sizeKb="108"/>
+    <snapshot id="2296916" createTime="2018-11-28T17:35:01.362-05:00" sizeKb="343"/>
+    <snapshot id="2294318" createTime="2018-11-28T17:09:01.650-05:00" sizeKb="235"/>
+    <snapshot id="2291728" createTime="2018-11-28T16:43:02.315-05:00" sizeKb="108"/>
+    <snapshot id="2289168" createTime="2018-11-28T16:17:02.322-05:00" sizeKb="214"/>
+    <snapshot id="2286587" createTime="2018-11-28T15:51:02.819-05:00" sizeKb="108"/>
+    <snapshot id="2284027" createTime="2018-11-28T15:25:02.998-05:00" sizeKb="167"/>
+    <snapshot id="2281452" createTime="2018-11-28T14:59:02.734-05:00" sizeKb="111"/>
+    <snapshot id="2278888" createTime="2018-11-28T14:33:03.398-05:00" sizeKb="105"/>
+    <snapshot id="2277599" createTime="2018-11-28T14:20:03.124-05:00" sizeKb="1142"/>
+    <snapshot id="2276214" createTime="2018-11-28T14:07:02.998-05:00" sizeKb="211"/>
+    <snapshot id="2273629" createTime="2018-11-28T13:41:03.464-05:00" sizeKb="108"/>
+    <snapshot id="2271069" createTime="2018-11-28T13:15:03.119-05:00" sizeKb="200"/>
+    <snapshot id="2268490" createTime="2018-11-28T12:49:05.695-05:00" sizeKb="108"/>
+    <snapshot id="2265930" createTime="2018-11-28T12:23:06.184-05:00" sizeKb="264"/>
+    <snapshot id="2263333" createTime="2018-11-28T11:57:06.200-05:00" sizeKb="108"/>
+    <snapshot id="2260773" createTime="2018-11-28T11:31:07.442-05:00" sizeKb="108"/>
+    <snapshot id="2258213" createTime="2018-11-28T11:05:07.440-05:00" sizeKb="641"/>
+    <snapshot id="2255583" createTime="2018-11-28T10:39:09.091-05:00" sizeKb="168"/>
+    <snapshot id="2253005" createTime="2018-11-28T10:13:08.800-05:00" sizeKb="263"/>
+    <snapshot id="2250405" createTime="2018-11-28T09:47:08.754-05:00" sizeKb="108"/>
+    <snapshot id="2247845" createTime="2018-11-28T09:21:09.153-05:00" sizeKb="205"/>
+    <snapshot id="2245264" createTime="2018-11-28T08:55:09.099-05:00" sizeKb="108"/>
+    <snapshot id="2242704" createTime="2018-11-28T08:29:08.941-05:00" sizeKb="134"/>
+    <snapshot id="2240132" createTime="2018-11-28T08:03:09.231-05:00" sizeKb="200"/>
+    <snapshot id="2237556" createTime="2018-11-28T07:37:09.816-05:00" sizeKb="108"/>
+    <snapshot id="2234996" createTime="2018-11-28T07:11:09.962-05:00" sizeKb="200"/>
+    <snapshot id="2232417" createTime="2018-11-28T06:45:10.052-05:00" sizeKb="108"/>
+</consistencyGroupSnapshots>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/facbea21/libcloud/test/compute/test_nttcis.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_nttcis.py b/libcloud/test/compute/test_nttcis.py
index 7f73473..cbc4fdb 100644
--- a/libcloud/test/compute/test_nttcis.py
+++ b/libcloud/test/compute/test_nttcis.py
@@ -1,5 +1,5 @@
 import pytest
-
+from dateutil.parser import parse
 
 import sys
 from types import GeneratorType
@@ -1844,6 +1844,82 @@ def test_ex_list_tags_ALLPARAMS(driver):
     assert len(tags) == 3
 
 
+def test_list_consistency_groups(driver):
+    cgs = driver.list_consistency_groups()
+    assert isinstance(cgs, list)
+
+
+def test_list_cg_by_src_net_domain(driver):
+    nd = "f9d6a249-c922-4fa1-9f0f-de5b452c4026"
+    cgs = driver.list_consistency_groups(source_network_domain_id=nd)
+    assert cgs[0].name == "sdk_test2_cg"
+
+
+def test_list_cg_by_name(driver):
+    NttCisMockHttp.type = "CG_BY_NAME"
+    name = "sdk_test2_cg"
+    cg = driver.list_consistency_groups(name=name)
+    assert cg[0].id == "195a426b-4559-4c79-849e-f22cdf2bfb6e"
+
+
+def test_get_consistency_group_by_id(driver):
+    NttCisMockHttp.type = None
+    cgs = driver.list_consistency_groups()
+    cg_id = [i for i in cgs if i.name == "sdk_test2_cg"][0].id
+    cg = driver.get_consistency_group(cg_id)
+    assert hasattr(cg, 'description')
+
+
+def test_get_drs_snapshots(driver):
+    NttCisMockHttp.type = None
+    cgs = driver.list_consistency_groups()
+    cg_id = [i for i in cgs if i.name == "sdk_test2_cg"][0].id
+    snaps = driver.list_consistency_group_snapshots(cg_id)
+    assert hasattr(snaps, 'journalUsageGb')
+
+
+def test_get_drs_snapshots_by_min_max(driver):
+    cgs = driver.list_consistency_groups()
+    cg_id = [i for i in cgs if i.name == "sdk_test2_cg"][0].id
+    snaps = driver.list_consistency_group_snapshots(
+        cg_id,
+        create_time_min="2018-11-28T00:00:00.000Z",
+        create_time_max="2018-11-29T00:00:00.000Z")
+    for snap in snaps.snapshot:
+        assert (parse(snaps.snapshot[0].createTime) < parse(snap.createTime)) is False
+
+
+def test_get_drs_snapshots_by_min(driver):
+    cgs = driver.list_consistency_groups()
+    cg_id = [i for i in cgs if i.name == "sdk_test2_cg"][0].id
+    snaps = driver.list_consistency_group_snapshots(
+        cg_id,
+        create_time_min="2018-11-29T00:00:00.000-05:00")
+    for snap in snaps.snapshot:
+        assert (parse(snaps.snapshot[0].createTime) < parse(snap.createTime)) is False
+
+
+def test_expand_drs_journal(driver):
+    cgs = driver.list_consistency_groups(name="sdk_test2_cg")
+    cg_id = cgs[0].id
+    expand_by = "100"
+    result = driver.expand_journal(cg_id, expand_by)
+    assert result is True
+
+
+def test_start_drs_snapshot_preview(driver):
+    cg_id = "195a426b-4559-4c79-849e-f22cdf2bfb6e"
+    snapshot_id = "3893"
+    result = driver.start_drs_failover_preview(cg_id, snapshot_id)
+    assert result is True
+
+
+def test_stop_drs_snapshot_preivew(driver):
+    cg_id = "195a426b-4559-4c79-849e-f22cdf2bfb6e"
+    result = driver.stop_drs_failover_preview(cg_id)
+    assert result is True
+
+
 class InvalidRequestError(Exception):
     def __init__(self, tag):
         super(InvalidRequestError, self).__init__("Invalid Request - %s" % tag)
@@ -1872,6 +1948,22 @@ class NttCisMockHttp(MockHttp):
         body = self.fixtures.load('oec_0_9_myaccount.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _oec_0_9_myaccount_NET_DOMAIN(self, method, url, body, headers):
+        body = self.fixtures.load('oec_0_9_myaccount.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _oec_0_9_myaccount_CG_BY_NAME(self, method, url, body, headers):
+        body = self.fixtures.load('oec_0_9_myaccount.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _oec_0_9_myaccount_MIN_MAX(self, method, url, body, headers):
+        body = self.fixtures.load('oec_0_9_myaccount.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _oec_0_9_myaccount_MIN(self, method, url, body, headers):
+        body = self.fixtures.load('oec_0_9_myaccount.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
     def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation(self, method, url, body, headers):
         body = self.fixtures.load(
             'networkWithLocation.xml')
@@ -2107,7 +2199,7 @@ class NttCisMockHttp(MockHttp):
             'server_startServer_INPROGRESS.xml')
         return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
 
-    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer(self, method, url, body, headers):
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_sna_compute_hutdownServer(self, method, url, body, headers):
         request = ET.fromstring(body)
         if request.tag != "{urn:didata.com:api:cloud:types}shutdownServer":
             raise InvalidRequestError(request.tag)
@@ -3108,3 +3200,73 @@ class NttCisMockHttp(MockHttp):
             "disable_server_snapshot_service.xml"
         )
         return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_consistencyGroup(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "list_consistency_groups.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_consistencyGroup_NET_DOMAIN(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "cg_by_src_network_domain.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_consistencyGroup_CG_BY_NAME(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "get_cg_by_name_or_id.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_consistencyGroup_195a426b_4559_4c79_849e_f22cdf2bfb6e(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "get_cg_by_name_or_id.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_snapshot(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "list_drs_snapshots.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_snapshot_MIN_MAX(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "drs_snap_shots_by_min_max_time.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_snapshot_MIN(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "drs_snap_shots_by_min.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_expandJournal(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "drs_expand_journal.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_startPreviewSnapshot(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "drs_start_failover_preview.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]
+
+    def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_consistencyGroup_stopPreviewSnapshot(
+        self, method, url, body, headers):
+        body = self.fixtures.load(
+            "drs_stop_failover_preview.xml"
+        )
+        return httplib.OK, body, {}, httplib.responses[httplib.OK]


Mime
View raw message