<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://wiki.openstack.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Alex+Meade</id>
		<title>OpenStack - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.openstack.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Alex+Meade"/>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/wiki/Special:Contributions/Alex_Meade"/>
		<updated>2026-07-10T12:40:13Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.28.2</generator>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_CI&amp;diff=104338</id>
		<title>ThirdPartySystems/NetApp CI</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_CI&amp;diff=104338"/>
				<updated>2016-02-16T21:54:23Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ThirdPartySystemInfo|name=NetApp CI&lt;br /&gt;
|account=netapp-ci&lt;br /&gt;
|contact= xdl-openstack-jenkins@netapp.com, andrew.kerr@netapp.com (akerr), alex.meade@netapp.com (ameade)&lt;br /&gt;
|intent=Test Openstack with NetApp Cinder and Manila drivers using storage arrays&lt;br /&gt;
|structure=Nodepool, Zuul, Jenkins, modified upstream components with local configuration&lt;br /&gt;
|method=Using Zuul to connect to Gerrit&lt;br /&gt;
|programs=Cinder, Manila&lt;br /&gt;
|status= Currently reporting on both Cinder and Manila&lt;br /&gt;
|recheck=run-netapp-ci}}&lt;br /&gt;
'''Recheck trigger:''' &amp;quot;run-netapp-ci&amp;quot;&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_CI&amp;diff=103932</id>
		<title>ThirdPartySystems/NetApp CI</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_CI&amp;diff=103932"/>
				<updated>2016-02-11T18:09:54Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ThirdPartySystemInfo|name=NetApp CI&lt;br /&gt;
|account=netapp-ci&lt;br /&gt;
|contact= xdl-openstack-jenkins@netapp.com, andrew.kerr@netapp.com (akerr), alex.meade@netapp.com (ameade)&lt;br /&gt;
|intent=Test Openstack with NetApp Cinder and Manila drivers using storage arrays&lt;br /&gt;
|structure=Nodepool, Zuul, Jenkins, modified upstream components with local configuration&lt;br /&gt;
|method=Using Zuul to connect to Gerrit&lt;br /&gt;
|programs=Cinder, Manila&lt;br /&gt;
|status=Not Reporting, Experiencing technical difficulties with a provider.&lt;br /&gt;
|recheck=run-netapp-ci}}&lt;br /&gt;
'''Recheck trigger:''' &amp;quot;run-netapp-ci&amp;quot;&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=102340</id>
		<title>Manila/design/manila-mitaka-data-replication</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=102340"/>
				<updated>2016-01-27T18:31:53Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Example Conf */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=Manila Disaster Recovery / Data Replication Design=&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Replicated shares will be implemented in Manila without adding any new services or any new drivers. The code for creating replicated shares and for adding/removing replicas and other replication-related operations will all go into the existing share drivers. The most significant change required to allow this will be that share drivers will be responsible for communicating with ALL storage controllers necessary to achieve any replication tasks, even if that involves sending commands to other storage controllers in other AZs.&lt;br /&gt;
&lt;br /&gt;
While we can't know how every storage controller works and how each vendor will implement replication, this approach should give driver writers all the flexibility needed to implement what they need with minimal added complexity in the Manila core. There are already examples of drivers reading config sections for other drivers when a operation requires communicating with 2 backends. The Manila Share Manager itself is expected to communicate all necessary backend details for share replicas that exist across AZs to a backend which it requests an operation upon.&lt;br /&gt;
&lt;br /&gt;
Intra-AZ replication is supported, but in an ideal solution, AZs should be perceived as failure domains. So this feature tends to shine in an inter-AZ replication use case. &lt;br /&gt;
&lt;br /&gt;
===Supported Replication Types===&lt;br /&gt;
There are 3 styles of DR that we would like to support in the long run:&lt;br /&gt;
&lt;br /&gt;
# writable - Amazon EFS-style synchronously replicated shares where all replicas are writable. Promotion it not supported and not needed.&lt;br /&gt;
# readable - Mirror-style replication with a primary (writable) copy and one or more secondary (read-only) copies which can become writable after a promotion of the secondary.&lt;br /&gt;
# dr - Generalized replication with secondary copies that are inaccessible until after a promotion of one of the secondary copies.&lt;br /&gt;
&lt;br /&gt;
===Replica States===&lt;br /&gt;
Each replica has a ''replica_state'' which has 4 possible values:&lt;br /&gt;
&lt;br /&gt;
# active - All writable replicas are active.&lt;br /&gt;
# in_sync - Passive replica which is up to date with the active replica, and can be promoted to active.&lt;br /&gt;
# out_of_sync - Passive replica which has gone out of date, or new replica that is not yet up to date.&lt;br /&gt;
# error - Either the scheduler failed to schedule this replica or some irrecoverable damage occurred during promotion of a non-active replica. Drivers may set the ''replica_state'' to ''error'' if some irrecoverable damage to the replica is discovered at any point during its existence. (through the periodic ''replica_state'' update)&lt;br /&gt;
[[File:Manila instance replication states.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New share state===&lt;br /&gt;
replication_change - New transient state triggered by a change of the active replica. Access to the share is cut off while in this state.&lt;br /&gt;
&lt;br /&gt;
===Promotion===&lt;br /&gt;
For '''readable''' and '''dr''' styles, we refer to the task of switching a non-active replica with the '''active''' replica as '''promotion'''. For the '''writable''' style of replication, '''promotion''' does not make sense since all replicas are '''active''' (writable) at all given points of time. Promotion of replicas with '''replica_state''' set to '''out_of_sync''' or '''error''' may be unsupported by the backend. However, we would like to allow the action as an administrator feature and such an attempt may be honored by backends if possible. &lt;br /&gt;
&lt;br /&gt;
When multiple replicas exist, multiple replication relationships between shares may need to be redefined at the backend. If the driver fails at this stage, the replicas may be left at an inconsistent state. The manager will set all replica instances to have '''replica_state''' and '''status''' to '''error'''. Recovery from this stage would require administrator intervention.&lt;br /&gt;
&lt;br /&gt;
==User Workflows==&lt;br /&gt;
====Creating a share supporting replication====&lt;br /&gt;
* Administrators can create a share type with extra-spec ''replication_type'', specifying the style of replication the backend supports.&lt;br /&gt;
* Users can use the share type to create a new share that allows/supports replication.&lt;br /&gt;
* A replicated share always starts out with one replica instance, the share itself. This should not be confused as the share having a replica already. The user can verify if the share has any replicas by requesting the details of the share.&lt;br /&gt;
&lt;br /&gt;
====Creating a replica====&lt;br /&gt;
* POST to /share-replicas&lt;br /&gt;
User has to specify the share name/id of the share that is supposed to be replicated, an availability zone for the replica to exist in and optionally a share_network_id.&lt;br /&gt;
According to existing design, replicas of a share cannot exist in the same availability zone as the share itself.&lt;br /&gt;
* A newly created share_replica starts out in ''out_of_sync'' state and might transition to ''in_sync'' state when the driver reports this state.&lt;br /&gt;
&lt;br /&gt;
====Listing and showing replicas====&lt;br /&gt;
* GET from /share-replicas&lt;br /&gt;
User can list all replicas and verify their ''status'' and ''replica_state''.&lt;br /&gt;
* GET from /share-replicas?share_id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
User can list replicas for a particular share.&lt;br /&gt;
* GET from /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
User can view details of a replica.&lt;br /&gt;
&lt;br /&gt;
====Promoting a non-active replica====&lt;br /&gt;
* POST to /share-replicas/action with body {'promote': None}&lt;br /&gt;
For replication types that permit promotion, the user can promote a replica with ''in_sync'' replica_state to ''active'' replica_state by initiating the ''promote_replica'' call.&lt;br /&gt;
* Only administrators can attempt promoting replicas with replica_state ''error'' or ''out_of_sync''.&lt;br /&gt;
&lt;br /&gt;
====Deleting Replicas====&lt;br /&gt;
* DELETE to /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
The user can delete a replica. The last ''active'' replica cannot be deleted using this ''delete_replica'' call.&lt;br /&gt;
&lt;br /&gt;
==System Workflows==&lt;br /&gt;
* Creating a share that supports replication&lt;br /&gt;
** Same process as creating a new share.&lt;br /&gt;
** The ''replication_type'' extra-spec from the share-type is copied over to the share''s data on the DB.&lt;br /&gt;
** Scheduler uses the ''replication_type'' extra-spec to filter available hosts and schedule the share on an appropriate backend that supports that specific style of ''replication_type''.&lt;br /&gt;
&lt;br /&gt;
* Creating a replica:&lt;br /&gt;
** Create a share instance on the database.&lt;br /&gt;
** Update the share instance ''replica_state'' to ''out_of_sync''.&lt;br /&gt;
** Cast a call to the scheduler to find an appropriate host to schedule the replica on.&lt;br /&gt;
** In the scheduler, find weighted host for the replica.&lt;br /&gt;
*** If host cannot be chosen, update the replica's ''status'' and ''replica_state'' on the Database to ''error''. Throw an exception.&lt;br /&gt;
** Cast the create_share_replica call to the driver based on the weighted host selection.&lt;br /&gt;
** Prior to invoking the driver's call, collate information regarding existing ''active'' replica instance, existing share access rules and the replica's share_server, pass these to the driver while invoking ''create_replica''.&lt;br /&gt;
** The driver may return ''export_locations'' and ''replica_state''. If they are returned, the database is updated with these values.&lt;br /&gt;
** If the ''replication_type'' is ''writable'', the driver MUST return the ''replica_state'' set to ''active''.&lt;br /&gt;
** All the access rules for the new replica are set to ''active'' state on the database.&lt;br /&gt;
** The driver may throw an exception, update the ''status'' and ''replica_state'' of the replica to ''error''.&lt;br /&gt;
&lt;br /&gt;
* Listing/showing shares:&lt;br /&gt;
** For shares that support replication, the result of listing/showing the share will have new fields, ''replication_type'': denoting the replication style supported and ''has_replicas'' to denote if the share has replicas.&lt;br /&gt;
** For replicated shares, the primary instance for the share must be preferred among those replicas that have a status ''replication_change'' or among those that have a replica_state set to ''active''.&lt;br /&gt;
&lt;br /&gt;
* Listing replicas&lt;br /&gt;
** For listing, Grab share instances from the database that have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** If share_id is provided, grab only share instances that belong to that share and have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** Limits and offsets must be respected on the list calls.&lt;br /&gt;
&lt;br /&gt;
* Promoting a non-active replica:&lt;br /&gt;
** If replica is already active, do nothing.&lt;br /&gt;
** Update the ''status'' of the replica being promoted to ''replication_change''.&lt;br /&gt;
** Grab all available replicas and invoke the appropriate driver''s promote_replica call by passing the available replicas and the new replica.&lt;br /&gt;
** If the driver throws an exception at this stage, there is a good chance that the replicas are somehow altered on the backend. Loop through the replicas and set their ''replica_state''s to ''error'' and leave the ''status'' unchanged. Also set the ''status'' of the replica that failed to promote to ''available'' as before this operation. The backend may choose to update the actual replica_state during the replica monitoring call.&lt;br /&gt;
** The driver may return an updated list of replicas. Update the ''export_locations'' and ''replica_state''s to the database.&lt;br /&gt;
** The ''status'' of the replica that was promoted should return to ''available'' from ''replication_change''.&lt;br /&gt;
&lt;br /&gt;
* Periodic replica update:&lt;br /&gt;
** The share manager implements a looping call with default interval of 5 minutes to query from each driver and each backend the ''replica_state'' of all non-active replicas that are associated with them.&lt;br /&gt;
** The driver is allowed to set the ''replica_state'' to ''in_sync'', ''out_of_sync'', and in exceptional cases, ''error''.&lt;br /&gt;
** If the driver sets the ''replica_state'' of a replica to ''error'', it is assumed that some irrecoverable damage has occured to the replica instance. The ''status'' of the replica instance must be set to ''error'' as well.&lt;br /&gt;
&lt;br /&gt;
* Deleting a share replica&lt;br /&gt;
** If the replica had no host, it is simply removed from the database.&lt;br /&gt;
** The ''status'' of the replica is set to ''deleting'' on the database and the appropriate driver method is called to delete the replica.&lt;br /&gt;
** If the driver fails to delete the replica, the ''status'' of the replica is updated to ''error_deleting'' on the database.&lt;br /&gt;
** If the driver returns without errors, the replica instance is removed from the database.&lt;br /&gt;
&lt;br /&gt;
==Scheduler Impact==&lt;br /&gt;
* The host_manager must update the ''replication_type'' capability from the backend. The backends must report this capability at the host/pool level.&lt;br /&gt;
* The filter_scheduler must then match the ''replication_type'' capability with the capability that the replication share_type demands.&lt;br /&gt;
* The ''replication_type'' must be one of the styles mentioned [[#Supported Replication Styles|above]].&lt;br /&gt;
&lt;br /&gt;
==DB Impact==&lt;br /&gt;
* Share Export Locations:&lt;br /&gt;
Preferred export locations will only be from the instances with ''replica_state'' set to ''active''.&lt;br /&gt;
  def export_locations(self):&lt;br /&gt;
      # TODO(gouthamr): Return AZ specific export locations for replicated&lt;br /&gt;
      #  shares&lt;br /&gt;
      # NOTE(gouthamr): For a replicated share, export locations of the&lt;br /&gt;
      # 'active' instances are taken, if 'available'.&lt;br /&gt;
      all_export_locations = []&lt;br /&gt;
      select_instances = list(filter(&lt;br /&gt;
          lambda x: x['replica_state'] == constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
          self.instances)) or self.instances&lt;br /&gt;
      for instance in select_instances:&lt;br /&gt;
          if instance['status'] == constants.STATUS_AVAILABLE:&lt;br /&gt;
              for export_location in instance.export_locations:&lt;br /&gt;
                  all_export_locations.append(export_location['path'])&lt;br /&gt;
    return all_export_locations&lt;br /&gt;
&lt;br /&gt;
* Share Instance:&lt;br /&gt;
Preferred instance will be an instance with ''status'' set to ''replication_change'' or any instance with ''status'' set to ''available'' and ''replica_state'' set to ''active''.&lt;br /&gt;
  def instance(self):&lt;br /&gt;
   # NOTE(gouthamr): The order of preference: status 'replication_change',&lt;br /&gt;
   # followed  by 'available' and 'creating'. If replicated share and&lt;br /&gt;
   # not undergoing a 'replication_change', only 'active' instances are&lt;br /&gt;
   # preferred.&lt;br /&gt;
   result = None&lt;br /&gt;
   if len(self.instances) &amp;gt; 0:&lt;br /&gt;
       order = [constants.STATUS_REPLICATION_CHANGE,&lt;br /&gt;
                constants.STATUS_AVAILABLE, constants.STATUS_CREATING]&lt;br /&gt;
       other_statuses = ([x['status'] for x in self.instances&lt;br /&gt;
                          if x['status'] not in order])&lt;br /&gt;
       order.extend(other_statuses)&lt;br /&gt;
       sorted_instances = sorted(&lt;br /&gt;
           self.instances, key=lambda x: order.index(x['status']))&lt;br /&gt;
       select_instances = sorted_instances&lt;br /&gt;
       if (select_instances[0]['status'] !=&lt;br /&gt;
               constants.STATUS_REPLICATION_CHANGE):&lt;br /&gt;
           select_instances = (&lt;br /&gt;
               list(filter(lambda x: x['replica_state'] ==&lt;br /&gt;
                           constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
                           sorted_instances)) or sorted_instances&lt;br /&gt;
           )&lt;br /&gt;
       result = select_instances[0]&lt;br /&gt;
   return result&lt;br /&gt;
&lt;br /&gt;
* New field on Share:&lt;br /&gt;
  replication_type = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
* New field on ShareInstance&lt;br /&gt;
  replica_state = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API Design==&lt;br /&gt;
  GET /share-replicas/&lt;br /&gt;
  GET /share-replicas?share-id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
  GET /share-replicas/&amp;lt;replica_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  POST /share-replicas/&amp;lt;share-id&amp;gt;&lt;br /&gt;
  Body:&lt;br /&gt;
  {&lt;br /&gt;
    'share_replica':&lt;br /&gt;
    {&lt;br /&gt;
      'availability_zone':&amp;lt;availability_zone_id&amp;gt;,&lt;br /&gt;
      'share_id':&amp;lt;share_id&amp;gt;,&lt;br /&gt;
      'share_network_id':&amp;lt;share_network_id&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  POST /share-replicas/&amp;lt;replica-id&amp;gt;/action&lt;br /&gt;
  Body:&lt;br /&gt;
  {'os-promote_replica': null}&lt;br /&gt;
&lt;br /&gt;
  DELETE /share-replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
&lt;br /&gt;
policy.json - All replication group policies should default to the default policy&lt;br /&gt;
    &amp;quot;share_replica:get_all&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:show&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:create&amp;quot; : &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:delete&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:promote&amp;quot;: &amp;quot;rule:default&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
Only a single replication driver method will be called at a time for a given share as they are locked by share id. Drivers should avoid raising errors to the manager for any of these methods. If the driver hits an issue it should attempt to return the correct model updates with the correct error states set to represent the actual state of the resources. A driver raising an exception will result in all replicas in the error status with the replica_state unchanged.&lt;br /&gt;
&lt;br /&gt;
  def create_replica(self, context, active_replica, new_replica,&lt;br /&gt;
                   access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Replicate the active replica to a new replica on this backend.&lt;br /&gt;
      :param context: Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              &amp;lt;models.ShareInstanceExportLocations&amp;gt;._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param new_replica: The share replica dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'out_of_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica being created.&lt;br /&gt;
      :return: (export_locations, replica_state)&lt;br /&gt;
      export_locations is a list of paths and replica_state is one of&lt;br /&gt;
      active, in-sync, out-of-sync or error.&lt;br /&gt;
      A backend supporting 'writable' type replication should return&lt;br /&gt;
      'active' as the replica_state.&lt;br /&gt;
      Export locations should be in the same format as returned by a&lt;br /&gt;
      share_create. This list may be empty or None.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
          .. code::&lt;br /&gt;
              [{'id': 'uuid', 'export_locations': ['export_path']}]&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def delete_replica(self, context, active_replica, replica,&lt;br /&gt;
                   share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Delete a replica.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param replica: Dictionary of the share replica being deleted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be deleted.&lt;br /&gt;
      :return: None.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def promote_replica(self, context, replica_list, replica, access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Promote a replica to 'active' replica state.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param replica_list: List of all replicas for a particular share.&lt;br /&gt;
      This list also contains the replica to be promoted. The 'active'&lt;br /&gt;
      replica will have its 'replica_state' attr set to 'active'.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          [&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'active',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              ...&lt;br /&gt;
          ]&lt;br /&gt;
      :param replica: Dictionary of the replica to be promoted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be promoted.&lt;br /&gt;
      :return: updated_replica_list or None&lt;br /&gt;
          The driver can return the updated list as in the request&lt;br /&gt;
          parameter. Changes that will be updated to the Database are:&lt;br /&gt;
          'export_locations' and 'replica_state'.&lt;br /&gt;
      :raises Exception&lt;br /&gt;
          This can be any exception derived from BaseException. This is&lt;br /&gt;
          re-raised by the manager after some necessary cleanup. If the&lt;br /&gt;
          driver raises an exception during promotion, it is assumed&lt;br /&gt;
          that all of the replicas of the share are in an inconsistent&lt;br /&gt;
          state. Recovery is only possible through the periodic update&lt;br /&gt;
          call and/or administrator intervention to correct the 'status'&lt;br /&gt;
          of the affected replicas if they become healthy again.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      def update_replica_state(self, context, replica, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Update the replica_state of a replica.&lt;br /&gt;
        Drivers should fix replication relationships that were broken if&lt;br /&gt;
        possible inside this method.&lt;br /&gt;
        :param context:Current context&lt;br /&gt;
        :param replica: Dictionary of the replica being updated.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
             .. code::&lt;br /&gt;
            {&lt;br /&gt;
            'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
            'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'deleted': False,&lt;br /&gt;
            'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
            'status': 'available',&lt;br /&gt;
            'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'terminated_at': None,&lt;br /&gt;
            'replica_state': 'active',&lt;br /&gt;
            'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
            'export_locations': [&lt;br /&gt;
                models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
            ],&lt;br /&gt;
            'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
            }&lt;br /&gt;
        :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None&lt;br /&gt;
        :return: replica_state&lt;br /&gt;
            replica_state - a str value denoting the replica_state that the&lt;br /&gt;
            replica can have. Valid values are 'in_sync' and 'out_of_sync'&lt;br /&gt;
            or None (to leave the current replica_state unchanged).&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
==Manila Client==&lt;br /&gt;
    share-replica-create Creates a replica&lt;br /&gt;
    share-replica-delete Remove one or more share replicas.&lt;br /&gt;
    share-replica-list  List share replicas.&lt;br /&gt;
    share-replica-promote Promote replica to active replica.&lt;br /&gt;
    share-replica-show  Show details about a replica.&lt;br /&gt;
&lt;br /&gt;
==Configuration Options==&lt;br /&gt;
replica_state_update_interval&lt;br /&gt;
This value, specified in seconds, determines how often the share manager will poll for the health (replica_state) of each replica instance.&lt;br /&gt;
&lt;br /&gt;
==First-Party Driver==&lt;br /&gt;
DR will require first-party driver support before it can be promoted from an experimental feature for two main reasons.&lt;br /&gt;
# A feature is not truly open if only a single vendor can develop it due to it only being supported by a proprietary driver. &lt;br /&gt;
# In order to ensure the quality of a feature, it must be testable in upstream gate.&lt;br /&gt;
&lt;br /&gt;
=FAQs=&lt;br /&gt;
# '''How do we deal with Network issues in multi-SVM replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If we choose to make replication a single-svm-only feature, the share-network API doesn't need to change. In order to support replication with share-networks, we also need to modify the share-network create API which allows creation of share networks with a table of AZ-to-subnet mappings. This approach allows us to keep a single share-network per share (with associated security service) while allowing the tenant to specify enough information that each share instance can be attached to the appropriate network in each AZ. Multi-AZ share networks would also be useful for non-replicated use cases.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we support Pool-level Replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Some vendors have suggested that certain backends can mirror groups of shares or whole pools more efficiently than individual shares. This design only addresses the mirroring of individual shares. In the future, we may allow allow replication of groups of shares, but only if those groups are contained within a single tenant and defined by the tenant.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''From where to where do we allow replication? Is it intra-cloud or inter-cloud? Do we allow replication to something that's not managed by Manila?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Intra-cloud. Replicating to something outside of Manila allows a bit more freedom, but with significantly less value, because there's practically nothing we can do to automate the failover/failback portion of a disaster. For use cases involving replication outside of Manila, we would need to involve other tools with more breadth/scope to manage the process.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Who configures the replication? The admin? The end user? The manila scheduler?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The end user. In the original design we presumed that the actual replication relationships should be hidden from the end user, but this doesn't match well with the concept of AZs that we are adding to Manila. If the users need to have control over which AZ the primary copy of their data lives in, then they also need to control where the other copies live. This means that the administrator's job is to ensure that for any share type that is replicated, it can be replicated from any AZ to any other AZ.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Is replication supported only intra-region or inter-region as well? How about intra-AZ vs inter-AZ?''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This design is for intra-region only. Inter-region replication is clearly a feature we want, but it would look pretty different from intra-region replication; this design does not cover that. Intra-AZ replication is supported, however inter-AZ replication is recommended as AZs should be perceived as failure domains.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Unanswered Questions=&lt;br /&gt;
# '''Is there no way to achieve non-disruptive failover?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(bswartz) I would love to find out that our initial intuition here is wrong, because it would change a lot of aspects of the design. It's worth spending time to brainstorm and research possibilities in this area. So far the most promising ideas involve:&lt;br /&gt;
#*Using VirtFS to mediate filesystem access and achieving non-disruptive failover that way&lt;br /&gt;
#*Using some kind of agent inside the guests to mediate file access&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Can a replica have a different share_type? There is a valid use case where a user would want to create a share replica on backend with different capabilities than the one the original share resides on. For instance, replicas might need to be on a less expensive backend. In that case, can the replica have a different share_type altogether?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;quot;Currently&amp;quot;, we inherit the share_type of the share and believe that replication has to be on symmetric terms, where both backends have similar capabilities.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''Can we allow the driver to restrict replication support between available backends? Backends may support replication to other compatible backends only. Hence, they must report some sort of information to the scheduler so that when creating a replica for an existing share, the scheduler would use that information to schedule the creation of the replica. What information should this be?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) We're investigating including 'driver_class_name' in a ReplicationFilter, including the possibility of backend reported configuration, 'replication_partners'.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How are access rules persisted across replicas/share instances?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#*Do all replicas have the same access rules applied? (gouthamr): This is Currently being pursued&lt;br /&gt;
#*Should access rules be applied only to &amp;quot;active&amp;quot; replicas?&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How does migration affect replicated shares?'''&lt;br /&gt;
#*(gouthamr)In the Tokyo summit, it was decided that we currently disallow migration of a share that has replicas. The replication relationships must be broken and reestablished after the migration is complete in order to migrate a share with replicas.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we need an API to initiate a sync? (resync or force-update)''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This is a great idea and one certain use case is during planned failovers. (gouthamr)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''How to recover from promotion failures?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) Currently, if some exception occurs at the driver level, the replicas are rendered useless. Should we provide escape hatches to avoid complete loss in case these are recoverable exceptions? The administrator has the ability to 'reset-state' and affect the 'status' of any replica. Currently, there exists no API to 'reset-replica-state' for a replica.&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
These examples assume that the replicas exist in different AZs.&lt;br /&gt;
&lt;br /&gt;
== Writable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=writeable&lt;br /&gt;
# Administrator creates a new share_type called foo&lt;br /&gt;
# Administrator sets replication_type=writeable extra spec on share type foo&lt;br /&gt;
# User creates new share of type foo in AZ b1&lt;br /&gt;
# Share is created with replication_type=writeable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to active (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 writes some data to the share, which is immediately visible to client1&lt;br /&gt;
&lt;br /&gt;
== Readable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=readable&lt;br /&gt;
# Administrator creates a new share_type called bar&lt;br /&gt;
# Administrator sets replication_type=readable extra spec on share type bar&lt;br /&gt;
# User creates new share of type bar in AZ b1&lt;br /&gt;
# Share is created with replication_type=readable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to in_sync (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 cannot write data to the share but continues to see updates&lt;br /&gt;
&lt;br /&gt;
== Failover/failback example ==&lt;br /&gt;
&lt;br /&gt;
(Continued from above)&lt;br /&gt;
# An outage occurs in AZ b1&lt;br /&gt;
# Administrator sends out a bulletin about the outage to his users &amp;quot;the power transformer in b1 turned to slag, it will be 12 hours before it can be replaced, please bear with us, yada yada&amp;quot;&lt;br /&gt;
# User notices that his application on client1 is no longer running, and investigates&lt;br /&gt;
# User finds out that client1 is gone, and reads a bulletin from the admin explaining why&lt;br /&gt;
# User notes that the b1 replica is his share is still active and the b2 replica is in_sync, while the state of the share is available&lt;br /&gt;
# User calls set active replica to AZ b2 on his share&lt;br /&gt;
# The share goes to state replication_change and access to the share is briefly lost on client2&lt;br /&gt;
# The state of replica b2 changes to active and the state of replica b1 changes to out_of_sync after Manila fails to contact the original primary. The state of the share changes back to available, and access is restored on client2&lt;br /&gt;
# User starts his application on client2, and the application recovers from an apparent crash, with a consistent copy of the application's data&lt;br /&gt;
# User application is back up and running, disaster is averted&lt;br /&gt;
# Eventually maintenance on the b1 AZ is completed, and all of the equipment is reactivated&lt;br /&gt;
# Administrator sends out a bulletin to his users about the outage ending &amp;quot;we replaced the transformer with a better one, everything is back online, thanks for your understanding, yada yada&amp;quot;&lt;br /&gt;
# Manila notices the out_of_sync replica is reachable and initiates a resync, bringing the b1 replica in_sync within a short time&lt;br /&gt;
# After some time, the users reads the bulletin and observes that his share is being replicated again. He decides to intentionally move back to b1.&lt;br /&gt;
# User gracefully shuts down his application, and flushes I/O&lt;br /&gt;
# User calls set active replica to AZ b1 on his share&lt;br /&gt;
# The share goes to state replication_change and no disruption is observed because the application is shut down&lt;br /&gt;
# The state of replica b1 changes to active and the state of replica b2 changes to in_sync after Manila reverses the replication again. The state of the share changes back to available&lt;br /&gt;
# User starts his application on client1, and the application starts cleanly, having been shut down gracefully&lt;br /&gt;
&lt;br /&gt;
=Implementation Progress=&lt;br /&gt;
===Core Work===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manila-share-replication Blueprint for Core API/Scheduler implementation]&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manilaclient-share-replication Blueprint for Client implementation]&lt;br /&gt;
&lt;br /&gt;
===Ex Driver Implementation===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/netapp-cdot-single-svm-replication Blueprint for cDOT Driver Implementation]&lt;br /&gt;
&lt;br /&gt;
=Older Design Pages=&lt;br /&gt;
* Replication Use Cases: https://wiki.openstack.org/wiki/Manila/Replication_Use_Cases&lt;br /&gt;
* Design Notes: https://wiki.openstack.org/wiki/Manila/Replication_Design_Notes&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=101073</id>
		<title>Manila/design/manila-mitaka-data-replication</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=101073"/>
				<updated>2016-01-13T14:03:55Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Example Conf */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=Manila Disaster Recovery / Data Replication Design=&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Replicated shares will be implemented in Manila without adding any new services or any new drivers. The code for creating replicated shares and for adding/removing replicas and other replication-related operations will all go into the existing share drivers. The most significant change required to allow this will be that share drivers will be responsible for communicating with ALL storage controllers necessary to achieve any replication tasks, even if that involves sending commands to other storage controllers in other AZs.&lt;br /&gt;
&lt;br /&gt;
While we can't know how every storage controller works and how each vendor will implement replication, this approach should give driver writers all the flexibility needed to implement what they need with minimal added complexity in the Manila core. There are already examples of drivers reading config sections for other drivers when a operation requires communicating with 2 backends. The Manila Share Manager itself is expected to communicate all necessary backend details for share replicas that exist across AZs to a backend which it requests an operation upon.&lt;br /&gt;
&lt;br /&gt;
Intra-AZ replication is supported, but in an ideal solution, AZs should be perceived as failure domains. So this feature tends to shine in an inter-AZ replication use case. &lt;br /&gt;
&lt;br /&gt;
===Supported Replication Types===&lt;br /&gt;
There are 3 styles of DR that we would like to support in the long run:&lt;br /&gt;
&lt;br /&gt;
# writable - Amazon EFS-style synchronously replicated shares where all replicas are writable. Promotion it not supported and not needed.&lt;br /&gt;
# readable - Mirror-style replication with a primary (writable) copy and one or more secondary (read-only) copies which can become writable after a promotion of the secondary.&lt;br /&gt;
# dr - Generalized replication with secondary copies that are inaccessible until after a promotion of one of the secondary copies.&lt;br /&gt;
&lt;br /&gt;
===Replica States===&lt;br /&gt;
Each replica has a ''replica_state'' which has 4 possible values:&lt;br /&gt;
&lt;br /&gt;
# active - All writable replicas are active.&lt;br /&gt;
# in_sync - Passive replica which is up to date with the active replica, and can be promoted to active.&lt;br /&gt;
# out_of_sync - Passive replica which has gone out of date, or new replica that is not yet up to date.&lt;br /&gt;
# error - Either the scheduler failed to schedule this replica or some irrecoverable damage occurred during promotion of a non-active replica. Drivers may set the ''replica_state'' to ''error'' if some irrecoverable damage to the replica is discovered at any point during its existence. (through the periodic ''replica_state'' update)&lt;br /&gt;
[[File:Manila instance replication states.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New share state===&lt;br /&gt;
replication_change - New transient state triggered by a change of the active replica. Access to the share is cut off while in this state.&lt;br /&gt;
&lt;br /&gt;
===Promotion===&lt;br /&gt;
For '''readable''' and '''dr''' styles, we refer to the task of switching a non-active replica with the '''active''' replica as '''promotion'''. For the '''writable''' style of replication, '''promotion''' does not make sense since all replicas are '''active''' (writable) at all given points of time. Promotion of replicas with '''replica_state''' set to '''out_of_sync''' or '''error''' may be unsupported by the backend. However, we would like to allow the action as an administrator feature and such an attempt may be honored by backends if possible. &lt;br /&gt;
&lt;br /&gt;
When multiple replicas exist, multiple replication relationships between shares may need to be redefined at the backend. If the driver fails at this stage, the replicas may be left at an inconsistent state. The manager will set all replica instances to have '''replica_state''' and '''status''' to '''error'''. Recovery from this stage would require administrator intervention.&lt;br /&gt;
&lt;br /&gt;
==User Workflows==&lt;br /&gt;
====Creating a share supporting replication====&lt;br /&gt;
* Administrators can create a share type with extra-spec ''replication_type'', specifying the style of replication the backend supports.&lt;br /&gt;
* Users can use the share type to create a new share that allows/supports replication.&lt;br /&gt;
* A replicated share always starts out with one replica instance, the share itself. This should not be confused as the share having a replica already. The user can verify if the share has any replicas by requesting the details of the share.&lt;br /&gt;
&lt;br /&gt;
====Creating a replica====&lt;br /&gt;
* POST to /share-replicas&lt;br /&gt;
User has to specify the share name/id of the share that is supposed to be replicated, an availability zone for the replica to exist in and optionally a share_network_id.&lt;br /&gt;
According to existing design, replicas of a share cannot exist in the same availability zone as the share itself.&lt;br /&gt;
* A newly created share_replica starts out in ''out_of_sync'' state and might transition to ''in_sync'' state when the driver reports this state.&lt;br /&gt;
&lt;br /&gt;
====Listing and showing replicas====&lt;br /&gt;
* GET from /share-replicas&lt;br /&gt;
User can list all replicas and verify their ''status'' and ''replica_state''.&lt;br /&gt;
* GET from /share-replicas?share_id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
User can list replicas for a particular share.&lt;br /&gt;
* GET from /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
User can view details of a replica.&lt;br /&gt;
&lt;br /&gt;
====Promoting a non-active replica====&lt;br /&gt;
* POST to /share-replicas/action with body {'promote': None}&lt;br /&gt;
For replication types that permit promotion, the user can promote a replica with ''in_sync'' replica_state to ''active'' replica_state by initiating the ''promote_replica'' call.&lt;br /&gt;
* Only administrators can attempt promoting replicas with replica_state ''error'' or ''out_of_sync''.&lt;br /&gt;
&lt;br /&gt;
====Deleting Replicas====&lt;br /&gt;
* DELETE to /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
The user can delete a replica. The last ''active'' replica cannot be deleted using this ''delete_replica'' call.&lt;br /&gt;
&lt;br /&gt;
==System Workflows==&lt;br /&gt;
* Creating a share that supports replication&lt;br /&gt;
** Same process as creating a new share.&lt;br /&gt;
** The ''replication_type'' extra-spec from the share-type is copied over to the share''s data on the DB.&lt;br /&gt;
** Scheduler uses the ''replication_type'' extra-spec to filter available hosts and schedule the share on an appropriate backend that supports that specific style of ''replication_type''.&lt;br /&gt;
&lt;br /&gt;
* Creating a replica:&lt;br /&gt;
** Create a share instance on the database.&lt;br /&gt;
** Update the share instance ''replica_state'' to ''out_of_sync''.&lt;br /&gt;
** Cast a call to the scheduler to find an appropriate host to schedule the replica on.&lt;br /&gt;
** In the scheduler, find weighted host for the replica.&lt;br /&gt;
*** If host cannot be chosen, update the replica's ''status'' and ''replica_state'' on the Database to ''error''. Throw an exception.&lt;br /&gt;
** Cast the create_share_replica call to the driver based on the weighted host selection.&lt;br /&gt;
** Prior to invoking the driver's call, collate information regarding existing ''active'' replica instance, existing share access rules and the replica's share_server, pass these to the driver while invoking ''create_replica''.&lt;br /&gt;
** The driver may return ''export_locations'' and ''replica_state''. If they are returned, the database is updated with these values.&lt;br /&gt;
** If the ''replication_type'' is ''writable'', the driver MUST return the ''replica_state'' set to ''active''.&lt;br /&gt;
** All the access rules for the new replica are set to ''active'' state on the database.&lt;br /&gt;
** The driver may throw an exception, update the ''status'' and ''replica_state'' of the replica to ''error''.&lt;br /&gt;
&lt;br /&gt;
* Listing/showing shares:&lt;br /&gt;
** For shares that support replication, the result of listing/showing the share will have new fields, ''replication_type'': denoting the replication style supported and ''has_replicas'' to denote if the share has replicas.&lt;br /&gt;
** For replicated shares, the primary instance for the share must be preferred among those replicas that have a status ''replication_change'' or among those that have a replica_state set to ''active''.&lt;br /&gt;
&lt;br /&gt;
* Listing replicas&lt;br /&gt;
** For listing, Grab share instances from the database that have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** If share_id is provided, grab only share instances that belong to that share and have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** Limits and offsets must be respected on the list calls.&lt;br /&gt;
&lt;br /&gt;
* Promoting a non-active replica:&lt;br /&gt;
** If replica is already active, do nothing.&lt;br /&gt;
** Update the ''status'' of the replica being promoted to ''replication_change''.&lt;br /&gt;
** Grab all available replicas and invoke the appropriate driver''s promote_replica call by passing the available replicas and the new replica.&lt;br /&gt;
** If the driver throws an exception at this stage, there is a good chance that the replicas are somehow altered on the backend. Loop through the replicas and set their ''replica_state''s to ''error'' and leave the ''status'' unchanged. Also set the ''status'' of the replica that failed to promote to ''available'' as before this operation. The backend may choose to update the actual replica_state during the replica monitoring call.&lt;br /&gt;
** The driver may return an updated list of replicas. Update the ''export_locations'' and ''replica_state''s to the database.&lt;br /&gt;
** The ''status'' of the replica that was promoted should return to ''available'' from ''replication_change''.&lt;br /&gt;
&lt;br /&gt;
* Periodic replica update:&lt;br /&gt;
** The share manager implements a looping call with default interval of 5 minutes to query from each driver and each backend the ''replica_state'' of all non-active replicas that are associated with them.&lt;br /&gt;
** The driver is allowed to set the ''replica_state'' to ''in_sync'', ''out_of_sync'', and in exceptional cases, ''error''.&lt;br /&gt;
** If the driver sets the ''replica_state'' of a replica to ''error'', it is assumed that some irrecoverable damage has occured to the replica instance. The ''status'' of the replica instance must be set to ''error'' as well.&lt;br /&gt;
&lt;br /&gt;
* Deleting a share replica&lt;br /&gt;
** If the replica had no host, it is simply removed from the database.&lt;br /&gt;
** The ''status'' of the replica is set to ''deleting'' on the database and the appropriate driver method is called to delete the replica.&lt;br /&gt;
** If the driver fails to delete the replica, the ''status'' of the replica is updated to ''error_deleting'' on the database.&lt;br /&gt;
** If the driver returns without errors, the replica instance is removed from the database.&lt;br /&gt;
&lt;br /&gt;
==Scheduler Impact==&lt;br /&gt;
* The host_manager must update the ''replication_type'' capability from the backend. The backends must report this capability at the host/pool level.&lt;br /&gt;
* The filter_scheduler must then match the ''replication_type'' capability with the capability that the replication share_type demands.&lt;br /&gt;
* The ''replication_type'' must be one of the styles mentioned [[#Supported Replication Styles|above]].&lt;br /&gt;
&lt;br /&gt;
==DB Impact==&lt;br /&gt;
* Share Export Locations:&lt;br /&gt;
Preferred export locations will only be from the instances with ''replica_state'' set to ''active''.&lt;br /&gt;
  def export_locations(self):&lt;br /&gt;
      # TODO(gouthamr): Return AZ specific export locations for replicated&lt;br /&gt;
      #  shares&lt;br /&gt;
      # NOTE(gouthamr): For a replicated share, export locations of the&lt;br /&gt;
      # 'active' instances are taken, if 'available'.&lt;br /&gt;
      all_export_locations = []&lt;br /&gt;
      select_instances = list(filter(&lt;br /&gt;
          lambda x: x['replica_state'] == constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
          self.instances)) or self.instances&lt;br /&gt;
      for instance in select_instances:&lt;br /&gt;
          if instance['status'] == constants.STATUS_AVAILABLE:&lt;br /&gt;
              for export_location in instance.export_locations:&lt;br /&gt;
                  all_export_locations.append(export_location['path'])&lt;br /&gt;
    return all_export_locations&lt;br /&gt;
&lt;br /&gt;
* Share Instance:&lt;br /&gt;
Preferred instance will be an instance with ''status'' set to ''replication_change'' or any instance with ''status'' set to ''available'' and ''replica_state'' set to ''active''.&lt;br /&gt;
  def instance(self):&lt;br /&gt;
   # NOTE(gouthamr): The order of preference: status 'replication_change',&lt;br /&gt;
   # followed  by 'available' and 'creating'. If replicated share and&lt;br /&gt;
   # not undergoing a 'replication_change', only 'active' instances are&lt;br /&gt;
   # preferred.&lt;br /&gt;
   result = None&lt;br /&gt;
   if len(self.instances) &amp;gt; 0:&lt;br /&gt;
       order = [constants.STATUS_REPLICATION_CHANGE,&lt;br /&gt;
                constants.STATUS_AVAILABLE, constants.STATUS_CREATING]&lt;br /&gt;
       other_statuses = ([x['status'] for x in self.instances&lt;br /&gt;
                          if x['status'] not in order])&lt;br /&gt;
       order.extend(other_statuses)&lt;br /&gt;
       sorted_instances = sorted(&lt;br /&gt;
           self.instances, key=lambda x: order.index(x['status']))&lt;br /&gt;
       select_instances = sorted_instances&lt;br /&gt;
       if (select_instances[0]['status'] !=&lt;br /&gt;
               constants.STATUS_REPLICATION_CHANGE):&lt;br /&gt;
           select_instances = (&lt;br /&gt;
               list(filter(lambda x: x['replica_state'] ==&lt;br /&gt;
                           constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
                           sorted_instances)) or sorted_instances&lt;br /&gt;
           )&lt;br /&gt;
       result = select_instances[0]&lt;br /&gt;
   return result&lt;br /&gt;
&lt;br /&gt;
* New field on Share:&lt;br /&gt;
  replication_type = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
* New field on ShareInstance&lt;br /&gt;
  replica_state = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API Design==&lt;br /&gt;
  GET /share-replicas/&lt;br /&gt;
  GET /share-replicas?share-id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
  GET /share-replicas/&amp;lt;replica_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  POST /share-replicas/&amp;lt;share-id&amp;gt;&lt;br /&gt;
  Body:&lt;br /&gt;
  {&lt;br /&gt;
    'share_replica':&lt;br /&gt;
    {&lt;br /&gt;
      'availability_zone':&amp;lt;availability_zone_id&amp;gt;,&lt;br /&gt;
      'share_id':&amp;lt;share_id&amp;gt;,&lt;br /&gt;
      'share_network_id':&amp;lt;share_network_id&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  POST /share-replicas/&amp;lt;replica-id&amp;gt;/action&lt;br /&gt;
  Body:&lt;br /&gt;
  {'os-promote_replica': null}&lt;br /&gt;
&lt;br /&gt;
  DELETE /share-replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
&lt;br /&gt;
policy.json - All replication group policies should default to the default policy&lt;br /&gt;
    &amp;quot;share_replica:get_all&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:show&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:create&amp;quot; : &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:delete&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:promote&amp;quot;: &amp;quot;rule:default&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
Only a single replication driver method will be called at a time for a given share as they are locked by share id. Drivers should avoid raising errors to the manager for any of these methods. If the driver hits an issue it should attempt to return the correct model updates with the correct error states set to represent the actual state of the resources. A driver raising an exception will result in all replicas in the error status with the replica_state unchanged.&lt;br /&gt;
&lt;br /&gt;
  def create_replica(self, context, active_replica, new_replica,&lt;br /&gt;
                   access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Replicate the active replica to a new replica on this backend.&lt;br /&gt;
      :param context: Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              &amp;lt;models.ShareInstanceExportLocations&amp;gt;._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param new_replica: The share replica dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'out_of_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica being created.&lt;br /&gt;
      :return: (export_locations, replica_state)&lt;br /&gt;
      export_locations is a list of paths and replica_state is one of&lt;br /&gt;
      active, in-sync, out-of-sync or error.&lt;br /&gt;
      A backend supporting 'writable' type replication should return&lt;br /&gt;
      'active' as the replica_state.&lt;br /&gt;
      Export locations should be in the same format as returned by a&lt;br /&gt;
      share_create. This list may be empty or None.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
          .. code::&lt;br /&gt;
              [{'id': 'uuid', 'export_locations': ['export_path']}]&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def delete_replica(self, context, active_replica, replica,&lt;br /&gt;
                   share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Delete a replica.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param replica: Dictionary of the share replica being deleted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be deleted.&lt;br /&gt;
      :return: None.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def promote_replica(self, context, replica_list, replica, access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Promote a replica to 'active' replica state.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param replica_list: List of all replicas for a particular share.&lt;br /&gt;
      This list also contains the replica to be promoted. The 'active'&lt;br /&gt;
      replica will have its 'replica_state' attr set to 'active'.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          [&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'active',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              ...&lt;br /&gt;
          ]&lt;br /&gt;
      :param replica: Dictionary of the replica to be promoted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be promoted.&lt;br /&gt;
      :return: updated_replica_list or None&lt;br /&gt;
          The driver can return the updated list as in the request&lt;br /&gt;
          parameter. Changes that will be updated to the Database are:&lt;br /&gt;
          'export_locations' and 'replica_state'.&lt;br /&gt;
      :raises Exception&lt;br /&gt;
          This can be any exception derived from BaseException. This is&lt;br /&gt;
          re-raised by the manager after some necessary cleanup. If the&lt;br /&gt;
          driver raises an exception during promotion, it is assumed&lt;br /&gt;
          that all of the replicas of the share are in an inconsistent&lt;br /&gt;
          state. Recovery is only possible through the periodic update&lt;br /&gt;
          call and/or administrator intervention to correct the 'status'&lt;br /&gt;
          of the affected replicas if they become healthy again.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      def update_replica_state(self, context, replica, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Update the replica_state of a replica.&lt;br /&gt;
        Drivers should fix replication relationships that were broken if&lt;br /&gt;
        possible inside this method.&lt;br /&gt;
        :param context:Current context&lt;br /&gt;
        :param replica: Dictionary of the replica being updated.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
             .. code::&lt;br /&gt;
            {&lt;br /&gt;
            'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
            'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'deleted': False,&lt;br /&gt;
            'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
            'status': 'available',&lt;br /&gt;
            'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'terminated_at': None,&lt;br /&gt;
            'replica_state': 'active',&lt;br /&gt;
            'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
            'export_locations': [&lt;br /&gt;
                models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
            ],&lt;br /&gt;
            'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
            }&lt;br /&gt;
        :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None&lt;br /&gt;
        :return: replica_state&lt;br /&gt;
            replica_state - a str value denoting the replica_state that the&lt;br /&gt;
            replica can have. Valid values are 'in_sync' and 'out_of_sync'&lt;br /&gt;
            or None (to leave the current replica_state unchanged).&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
==Manila Client==&lt;br /&gt;
    share-replica-create Creates a replica&lt;br /&gt;
    share-replica-delete Remove one or more share replicas.&lt;br /&gt;
    share-replica-list  List share replicas.&lt;br /&gt;
    share-replica-promote Promote replica to active replica.&lt;br /&gt;
    share-replica-show  Show details about a replica.&lt;br /&gt;
&lt;br /&gt;
==Example Conf==&lt;br /&gt;
 There must be stanzas containing information about each of the replication partners.&lt;br /&gt;
 [default]&lt;br /&gt;
 storage_availability_zone = az1&lt;br /&gt;
 enabled_backends = backend1&lt;br /&gt;
 [backend1]&lt;br /&gt;
 replication_partners = backend2&lt;br /&gt;
 [backend2]&lt;br /&gt;
 replication_partners = backend1&lt;br /&gt;
&lt;br /&gt;
==First-Party Driver==&lt;br /&gt;
DR will require first-party driver support before it can be promoted from an experimental feature for two main reasons.&lt;br /&gt;
# A feature is not truly open if only a single vendor can develop it due to it only being supported by a proprietary driver. &lt;br /&gt;
# In order to ensure the quality of a feature, it must be testable in upstream gate.&lt;br /&gt;
&lt;br /&gt;
=FAQs=&lt;br /&gt;
# '''How do we deal with Network issues in multi-SVM replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If we choose to make replication a single-svm-only feature, the share-network API doesn't need to change. In order to support replication with share-networks, we also need to modify the share-network create API which allows creation of share networks with a table of AZ-to-subnet mappings. This approach allows us to keep a single share-network per share (with associated security service) while allowing the tenant to specify enough information that each share instance can be attached to the appropriate network in each AZ. Multi-AZ share networks would also be useful for non-replicated use cases.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we support Pool-level Replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Some vendors have suggested that certain backends can mirror groups of shares or whole pools more efficiently than individual shares. This design only addresses the mirroring of individual shares. In the future, we may allow allow replication of groups of shares, but only if those groups are contained within a single tenant and defined by the tenant.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''From where to where do we allow replication? Is it intra-cloud or inter-cloud? Do we allow replication to something that's not managed by Manila?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Intra-cloud. Replicating to something outside of Manila allows a bit more freedom, but with significantly less value, because there's practically nothing we can do to automate the failover/failback portion of a disaster. For use cases involving replication outside of Manila, we would need to involve other tools with more breadth/scope to manage the process.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Who configures the replication? The admin? The end user? The manila scheduler?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The end user. In the original design we presumed that the actual replication relationships should be hidden from the end user, but this doesn't match well with the concept of AZs that we are adding to Manila. If the users need to have control over which AZ the primary copy of their data lives in, then they also need to control where the other copies live. This means that the administrator's job is to ensure that for any share type that is replicated, it can be replicated from any AZ to any other AZ.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Is replication supported only intra-region or inter-region as well? How about intra-AZ vs inter-AZ?''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This design is for intra-region only. Inter-region replication is clearly a feature we want, but it would look pretty different from intra-region replication; this design does not cover that. Intra-AZ replication is supported, however inter-AZ replication is recommended as AZs should be perceived as failure domains.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Unanswered Questions=&lt;br /&gt;
# '''Is there no way to achieve non-disruptive failover?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(bswartz) I would love to find out that our initial intuition here is wrong, because it would change a lot of aspects of the design. It's worth spending time to brainstorm and research possibilities in this area. So far the most promising ideas involve:&lt;br /&gt;
#*Using VirtFS to mediate filesystem access and achieving non-disruptive failover that way&lt;br /&gt;
#*Using some kind of agent inside the guests to mediate file access&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Can a replica have a different share_type? There is a valid use case where a user would want to create a share replica on backend with different capabilities than the one the original share resides on. For instance, replicas might need to be on a less expensive backend. In that case, can the replica have a different share_type altogether?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;quot;Currently&amp;quot;, we inherit the share_type of the share and believe that replication has to be on symmetric terms, where both backends have similar capabilities.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''Can we allow the driver to restrict replication support between available backends? Backends may support replication to other compatible backends only. Hence, they must report some sort of information to the scheduler so that when creating a replica for an existing share, the scheduler would use that information to schedule the creation of the replica. What information should this be?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) We're investigating including 'driver_class_name' in a ReplicationFilter, including the possibility of backend reported configuration, 'replication_partners'.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How are access rules persisted across replicas/share instances?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#*Do all replicas have the same access rules applied? (gouthamr): This is Currently being pursued&lt;br /&gt;
#*Should access rules be applied only to &amp;quot;active&amp;quot; replicas?&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How does migration affect replicated shares?'''&lt;br /&gt;
#*(gouthamr)In the Tokyo summit, it was decided that we currently disallow migration of a share that has replicas. The replication relationships must be broken and reestablished after the migration is complete in order to migrate a share with replicas.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we need an API to initiate a sync? (resync or force-update)''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This is a great idea and one certain use case is during planned failovers. (gouthamr)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''How to recover from promotion failures?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) Currently, if some exception occurs at the driver level, the replicas are rendered useless. Should we provide escape hatches to avoid complete loss in case these are recoverable exceptions? The administrator has the ability to 'reset-state' and affect the 'status' of any replica. Currently, there exists no API to 'reset-replica-state' for a replica.&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
These examples assume that the replicas exist in different AZs.&lt;br /&gt;
&lt;br /&gt;
== Writable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=writeable&lt;br /&gt;
# Administrator creates a new share_type called foo&lt;br /&gt;
# Administrator sets replication_type=writeable extra spec on share type foo&lt;br /&gt;
# User creates new share of type foo in AZ b1&lt;br /&gt;
# Share is created with replication_type=writeable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to active (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 writes some data to the share, which is immediately visible to client1&lt;br /&gt;
&lt;br /&gt;
== Readable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=readable&lt;br /&gt;
# Administrator creates a new share_type called bar&lt;br /&gt;
# Administrator sets replication_type=readable extra spec on share type bar&lt;br /&gt;
# User creates new share of type bar in AZ b1&lt;br /&gt;
# Share is created with replication_type=readable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to in_sync (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 cannot write data to the share but continues to see updates&lt;br /&gt;
&lt;br /&gt;
== Failover/failback example ==&lt;br /&gt;
&lt;br /&gt;
(Continued from above)&lt;br /&gt;
# An outage occurs in AZ b1&lt;br /&gt;
# Administrator sends out a bulletin about the outage to his users &amp;quot;the power transformer in b1 turned to slag, it will be 12 hours before it can be replaced, please bear with us, yada yada&amp;quot;&lt;br /&gt;
# User notices that his application on client1 is no longer running, and investigates&lt;br /&gt;
# User finds out that client1 is gone, and reads a bulletin from the admin explaining why&lt;br /&gt;
# User notes that the b1 replica is his share is still active and the b2 replica is in_sync, while the state of the share is available&lt;br /&gt;
# User calls set active replica to AZ b2 on his share&lt;br /&gt;
# The share goes to state replication_change and access to the share is briefly lost on client2&lt;br /&gt;
# The state of replica b2 changes to active and the state of replica b1 changes to out_of_sync after Manila fails to contact the original primary. The state of the share changes back to available, and access is restored on client2&lt;br /&gt;
# User starts his application on client2, and the application recovers from an apparent crash, with a consistent copy of the application's data&lt;br /&gt;
# User application is back up and running, disaster is averted&lt;br /&gt;
# Eventually maintenance on the b1 AZ is completed, and all of the equipment is reactivated&lt;br /&gt;
# Administrator sends out a bulletin to his users about the outage ending &amp;quot;we replaced the transformer with a better one, everything is back online, thanks for your understanding, yada yada&amp;quot;&lt;br /&gt;
# Manila notices the out_of_sync replica is reachable and initiates a resync, bringing the b1 replica in_sync within a short time&lt;br /&gt;
# After some time, the users reads the bulletin and observes that his share is being replicated again. He decides to intentionally move back to b1.&lt;br /&gt;
# User gracefully shuts down his application, and flushes I/O&lt;br /&gt;
# User calls set active replica to AZ b1 on his share&lt;br /&gt;
# The share goes to state replication_change and no disruption is observed because the application is shut down&lt;br /&gt;
# The state of replica b1 changes to active and the state of replica b2 changes to in_sync after Manila reverses the replication again. The state of the share changes back to available&lt;br /&gt;
# User starts his application on client1, and the application starts cleanly, having been shut down gracefully&lt;br /&gt;
&lt;br /&gt;
=Implementation Progress=&lt;br /&gt;
===Core Work===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manila-share-replication Blueprint for Core API/Scheduler implementation]&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manilaclient-share-replication Blueprint for Client implementation]&lt;br /&gt;
&lt;br /&gt;
===Ex Driver Implementation===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/netapp-cdot-single-svm-replication Blueprint for cDOT Driver Implementation]&lt;br /&gt;
&lt;br /&gt;
=Older Design Pages=&lt;br /&gt;
* Replication Use Cases: https://wiki.openstack.org/wiki/Manila/Replication_Use_Cases&lt;br /&gt;
* Design Notes: https://wiki.openstack.org/wiki/Manila/Replication_Design_Notes&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=101072</id>
		<title>Manila/design/manila-mitaka-data-replication</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=101072"/>
				<updated>2016-01-13T14:00:55Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=Manila Disaster Recovery / Data Replication Design=&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Replicated shares will be implemented in Manila without adding any new services or any new drivers. The code for creating replicated shares and for adding/removing replicas and other replication-related operations will all go into the existing share drivers. The most significant change required to allow this will be that share drivers will be responsible for communicating with ALL storage controllers necessary to achieve any replication tasks, even if that involves sending commands to other storage controllers in other AZs.&lt;br /&gt;
&lt;br /&gt;
While we can't know how every storage controller works and how each vendor will implement replication, this approach should give driver writers all the flexibility needed to implement what they need with minimal added complexity in the Manila core. There are already examples of drivers reading config sections for other drivers when a operation requires communicating with 2 backends. The Manila Share Manager itself is expected to communicate all necessary backend details for share replicas that exist across AZs to a backend which it requests an operation upon.&lt;br /&gt;
&lt;br /&gt;
Intra-AZ replication is supported, but in an ideal solution, AZs should be perceived as failure domains. So this feature tends to shine in an inter-AZ replication use case. &lt;br /&gt;
&lt;br /&gt;
===Supported Replication Types===&lt;br /&gt;
There are 3 styles of DR that we would like to support in the long run:&lt;br /&gt;
&lt;br /&gt;
# writable - Amazon EFS-style synchronously replicated shares where all replicas are writable. Promotion it not supported and not needed.&lt;br /&gt;
# readable - Mirror-style replication with a primary (writable) copy and one or more secondary (read-only) copies which can become writable after a promotion of the secondary.&lt;br /&gt;
# dr - Generalized replication with secondary copies that are inaccessible until after a promotion of one of the secondary copies.&lt;br /&gt;
&lt;br /&gt;
===Replica States===&lt;br /&gt;
Each replica has a ''replica_state'' which has 4 possible values:&lt;br /&gt;
&lt;br /&gt;
# active - All writable replicas are active.&lt;br /&gt;
# in_sync - Passive replica which is up to date with the active replica, and can be promoted to active.&lt;br /&gt;
# out_of_sync - Passive replica which has gone out of date, or new replica that is not yet up to date.&lt;br /&gt;
# error - Either the scheduler failed to schedule this replica or some irrecoverable damage occurred during promotion of a non-active replica. Drivers may set the ''replica_state'' to ''error'' if some irrecoverable damage to the replica is discovered at any point during its existence. (through the periodic ''replica_state'' update)&lt;br /&gt;
[[File:Manila instance replication states.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New share state===&lt;br /&gt;
replication_change - New transient state triggered by a change of the active replica. Access to the share is cut off while in this state.&lt;br /&gt;
&lt;br /&gt;
===Promotion===&lt;br /&gt;
For '''readable''' and '''dr''' styles, we refer to the task of switching a non-active replica with the '''active''' replica as '''promotion'''. For the '''writable''' style of replication, '''promotion''' does not make sense since all replicas are '''active''' (writable) at all given points of time. Promotion of replicas with '''replica_state''' set to '''out_of_sync''' or '''error''' may be unsupported by the backend. However, we would like to allow the action as an administrator feature and such an attempt may be honored by backends if possible. &lt;br /&gt;
&lt;br /&gt;
When multiple replicas exist, multiple replication relationships between shares may need to be redefined at the backend. If the driver fails at this stage, the replicas may be left at an inconsistent state. The manager will set all replica instances to have '''replica_state''' and '''status''' to '''error'''. Recovery from this stage would require administrator intervention.&lt;br /&gt;
&lt;br /&gt;
==User Workflows==&lt;br /&gt;
====Creating a share supporting replication====&lt;br /&gt;
* Administrators can create a share type with extra-spec ''replication_type'', specifying the style of replication the backend supports.&lt;br /&gt;
* Users can use the share type to create a new share that allows/supports replication.&lt;br /&gt;
* A replicated share always starts out with one replica instance, the share itself. This should not be confused as the share having a replica already. The user can verify if the share has any replicas by requesting the details of the share.&lt;br /&gt;
&lt;br /&gt;
====Creating a replica====&lt;br /&gt;
* POST to /share-replicas&lt;br /&gt;
User has to specify the share name/id of the share that is supposed to be replicated, an availability zone for the replica to exist in and optionally a share_network_id.&lt;br /&gt;
According to existing design, replicas of a share cannot exist in the same availability zone as the share itself.&lt;br /&gt;
* A newly created share_replica starts out in ''out_of_sync'' state and might transition to ''in_sync'' state when the driver reports this state.&lt;br /&gt;
&lt;br /&gt;
====Listing and showing replicas====&lt;br /&gt;
* GET from /share-replicas&lt;br /&gt;
User can list all replicas and verify their ''status'' and ''replica_state''.&lt;br /&gt;
* GET from /share-replicas?share_id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
User can list replicas for a particular share.&lt;br /&gt;
* GET from /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
User can view details of a replica.&lt;br /&gt;
&lt;br /&gt;
====Promoting a non-active replica====&lt;br /&gt;
* POST to /share-replicas/action with body {'promote': None}&lt;br /&gt;
For replication types that permit promotion, the user can promote a replica with ''in_sync'' replica_state to ''active'' replica_state by initiating the ''promote_replica'' call.&lt;br /&gt;
* Only administrators can attempt promoting replicas with replica_state ''error'' or ''out_of_sync''.&lt;br /&gt;
&lt;br /&gt;
====Deleting Replicas====&lt;br /&gt;
* DELETE to /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
The user can delete a replica. The last ''active'' replica cannot be deleted using this ''delete_replica'' call.&lt;br /&gt;
&lt;br /&gt;
==System Workflows==&lt;br /&gt;
* Creating a share that supports replication&lt;br /&gt;
** Same process as creating a new share.&lt;br /&gt;
** The ''replication_type'' extra-spec from the share-type is copied over to the share''s data on the DB.&lt;br /&gt;
** Scheduler uses the ''replication_type'' extra-spec to filter available hosts and schedule the share on an appropriate backend that supports that specific style of ''replication_type''.&lt;br /&gt;
&lt;br /&gt;
* Creating a replica:&lt;br /&gt;
** Create a share instance on the database.&lt;br /&gt;
** Update the share instance ''replica_state'' to ''out_of_sync''.&lt;br /&gt;
** Cast a call to the scheduler to find an appropriate host to schedule the replica on.&lt;br /&gt;
** In the scheduler, find weighted host for the replica.&lt;br /&gt;
*** If host cannot be chosen, update the replica's ''status'' and ''replica_state'' on the Database to ''error''. Throw an exception.&lt;br /&gt;
** Cast the create_share_replica call to the driver based on the weighted host selection.&lt;br /&gt;
** Prior to invoking the driver's call, collate information regarding existing ''active'' replica instance, existing share access rules and the replica's share_server, pass these to the driver while invoking ''create_replica''.&lt;br /&gt;
** The driver may return ''export_locations'' and ''replica_state''. If they are returned, the database is updated with these values.&lt;br /&gt;
** If the ''replication_type'' is ''writable'', the driver MUST return the ''replica_state'' set to ''active''.&lt;br /&gt;
** All the access rules for the new replica are set to ''active'' state on the database.&lt;br /&gt;
** The driver may throw an exception, update the ''status'' and ''replica_state'' of the replica to ''error''.&lt;br /&gt;
&lt;br /&gt;
* Listing/showing shares:&lt;br /&gt;
** For shares that support replication, the result of listing/showing the share will have new fields, ''replication_type'': denoting the replication style supported and ''has_replicas'' to denote if the share has replicas.&lt;br /&gt;
** For replicated shares, the primary instance for the share must be preferred among those replicas that have a status ''replication_change'' or among those that have a replica_state set to ''active''.&lt;br /&gt;
&lt;br /&gt;
* Listing replicas&lt;br /&gt;
** For listing, Grab share instances from the database that have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** If share_id is provided, grab only share instances that belong to that share and have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** Limits and offsets must be respected on the list calls.&lt;br /&gt;
&lt;br /&gt;
* Promoting a non-active replica:&lt;br /&gt;
** If replica is already active, do nothing.&lt;br /&gt;
** Update the ''status'' of the replica being promoted to ''replication_change''.&lt;br /&gt;
** Grab all available replicas and invoke the appropriate driver''s promote_replica call by passing the available replicas and the new replica.&lt;br /&gt;
** If the driver throws an exception at this stage, there is a good chance that the replicas are somehow altered on the backend. Loop through the replicas and set their ''replica_state''s to ''error'' and leave the ''status'' unchanged. Also set the ''status'' of the replica that failed to promote to ''available'' as before this operation. The backend may choose to update the actual replica_state during the replica monitoring call.&lt;br /&gt;
** The driver may return an updated list of replicas. Update the ''export_locations'' and ''replica_state''s to the database.&lt;br /&gt;
** The ''status'' of the replica that was promoted should return to ''available'' from ''replication_change''.&lt;br /&gt;
&lt;br /&gt;
* Periodic replica update:&lt;br /&gt;
** The share manager implements a looping call with default interval of 5 minutes to query from each driver and each backend the ''replica_state'' of all non-active replicas that are associated with them.&lt;br /&gt;
** The driver is allowed to set the ''replica_state'' to ''in_sync'', ''out_of_sync'', and in exceptional cases, ''error''.&lt;br /&gt;
** If the driver sets the ''replica_state'' of a replica to ''error'', it is assumed that some irrecoverable damage has occured to the replica instance. The ''status'' of the replica instance must be set to ''error'' as well.&lt;br /&gt;
&lt;br /&gt;
* Deleting a share replica&lt;br /&gt;
** If the replica had no host, it is simply removed from the database.&lt;br /&gt;
** The ''status'' of the replica is set to ''deleting'' on the database and the appropriate driver method is called to delete the replica.&lt;br /&gt;
** If the driver fails to delete the replica, the ''status'' of the replica is updated to ''error_deleting'' on the database.&lt;br /&gt;
** If the driver returns without errors, the replica instance is removed from the database.&lt;br /&gt;
&lt;br /&gt;
==Scheduler Impact==&lt;br /&gt;
* The host_manager must update the ''replication_type'' capability from the backend. The backends must report this capability at the host/pool level.&lt;br /&gt;
* The filter_scheduler must then match the ''replication_type'' capability with the capability that the replication share_type demands.&lt;br /&gt;
* The ''replication_type'' must be one of the styles mentioned [[#Supported Replication Styles|above]].&lt;br /&gt;
&lt;br /&gt;
==DB Impact==&lt;br /&gt;
* Share Export Locations:&lt;br /&gt;
Preferred export locations will only be from the instances with ''replica_state'' set to ''active''.&lt;br /&gt;
  def export_locations(self):&lt;br /&gt;
      # TODO(gouthamr): Return AZ specific export locations for replicated&lt;br /&gt;
      #  shares&lt;br /&gt;
      # NOTE(gouthamr): For a replicated share, export locations of the&lt;br /&gt;
      # 'active' instances are taken, if 'available'.&lt;br /&gt;
      all_export_locations = []&lt;br /&gt;
      select_instances = list(filter(&lt;br /&gt;
          lambda x: x['replica_state'] == constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
          self.instances)) or self.instances&lt;br /&gt;
      for instance in select_instances:&lt;br /&gt;
          if instance['status'] == constants.STATUS_AVAILABLE:&lt;br /&gt;
              for export_location in instance.export_locations:&lt;br /&gt;
                  all_export_locations.append(export_location['path'])&lt;br /&gt;
    return all_export_locations&lt;br /&gt;
&lt;br /&gt;
* Share Instance:&lt;br /&gt;
Preferred instance will be an instance with ''status'' set to ''replication_change'' or any instance with ''status'' set to ''available'' and ''replica_state'' set to ''active''.&lt;br /&gt;
  def instance(self):&lt;br /&gt;
   # NOTE(gouthamr): The order of preference: status 'replication_change',&lt;br /&gt;
   # followed  by 'available' and 'creating'. If replicated share and&lt;br /&gt;
   # not undergoing a 'replication_change', only 'active' instances are&lt;br /&gt;
   # preferred.&lt;br /&gt;
   result = None&lt;br /&gt;
   if len(self.instances) &amp;gt; 0:&lt;br /&gt;
       order = [constants.STATUS_REPLICATION_CHANGE,&lt;br /&gt;
                constants.STATUS_AVAILABLE, constants.STATUS_CREATING]&lt;br /&gt;
       other_statuses = ([x['status'] for x in self.instances&lt;br /&gt;
                          if x['status'] not in order])&lt;br /&gt;
       order.extend(other_statuses)&lt;br /&gt;
       sorted_instances = sorted(&lt;br /&gt;
           self.instances, key=lambda x: order.index(x['status']))&lt;br /&gt;
       select_instances = sorted_instances&lt;br /&gt;
       if (select_instances[0]['status'] !=&lt;br /&gt;
               constants.STATUS_REPLICATION_CHANGE):&lt;br /&gt;
           select_instances = (&lt;br /&gt;
               list(filter(lambda x: x['replica_state'] ==&lt;br /&gt;
                           constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
                           sorted_instances)) or sorted_instances&lt;br /&gt;
           )&lt;br /&gt;
       result = select_instances[0]&lt;br /&gt;
   return result&lt;br /&gt;
&lt;br /&gt;
* New field on Share:&lt;br /&gt;
  replication_type = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
* New field on ShareInstance&lt;br /&gt;
  replica_state = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API Design==&lt;br /&gt;
  GET /share-replicas/&lt;br /&gt;
  GET /share-replicas?share-id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
  GET /share-replicas/&amp;lt;replica_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  POST /share-replicas/&amp;lt;share-id&amp;gt;&lt;br /&gt;
  Body:&lt;br /&gt;
  {&lt;br /&gt;
    'share_replica':&lt;br /&gt;
    {&lt;br /&gt;
      'availability_zone':&amp;lt;availability_zone_id&amp;gt;,&lt;br /&gt;
      'share_id':&amp;lt;share_id&amp;gt;,&lt;br /&gt;
      'share_network_id':&amp;lt;share_network_id&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  POST /share-replicas/&amp;lt;replica-id&amp;gt;/action&lt;br /&gt;
  Body:&lt;br /&gt;
  {'os-promote_replica': null}&lt;br /&gt;
&lt;br /&gt;
  DELETE /share-replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
&lt;br /&gt;
policy.json - All replication group policies should default to the default policy&lt;br /&gt;
    &amp;quot;share_replica:get_all&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:show&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:create&amp;quot; : &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:delete&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:promote&amp;quot;: &amp;quot;rule:default&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
Only a single replication driver method will be called at a time for a given share as they are locked by share id. Drivers should avoid raising errors to the manager for any of these methods. If the driver hits an issue it should attempt to return the correct model updates with the correct error states set to represent the actual state of the resources. A driver raising an exception will result in all replicas in the error status with the replica_state unchanged.&lt;br /&gt;
&lt;br /&gt;
  def create_replica(self, context, active_replica, new_replica,&lt;br /&gt;
                   access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Replicate the active replica to a new replica on this backend.&lt;br /&gt;
      :param context: Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              &amp;lt;models.ShareInstanceExportLocations&amp;gt;._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param new_replica: The share replica dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'out_of_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica being created.&lt;br /&gt;
      :return: (export_locations, replica_state)&lt;br /&gt;
      export_locations is a list of paths and replica_state is one of&lt;br /&gt;
      active, in-sync, out-of-sync or error.&lt;br /&gt;
      A backend supporting 'writable' type replication should return&lt;br /&gt;
      'active' as the replica_state.&lt;br /&gt;
      Export locations should be in the same format as returned by a&lt;br /&gt;
      share_create. This list may be empty or None.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
          .. code::&lt;br /&gt;
              [{'id': 'uuid', 'export_locations': ['export_path']}]&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def delete_replica(self, context, active_replica, replica,&lt;br /&gt;
                   share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Delete a replica.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param replica: Dictionary of the share replica being deleted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be deleted.&lt;br /&gt;
      :return: None.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def promote_replica(self, context, replica_list, replica, access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Promote a replica to 'active' replica state.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param replica_list: List of all replicas for a particular share.&lt;br /&gt;
      This list also contains the replica to be promoted. The 'active'&lt;br /&gt;
      replica will have its 'replica_state' attr set to 'active'.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          [&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'active',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              ...&lt;br /&gt;
          ]&lt;br /&gt;
      :param replica: Dictionary of the replica to be promoted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be promoted.&lt;br /&gt;
      :return: updated_replica_list or None&lt;br /&gt;
          The driver can return the updated list as in the request&lt;br /&gt;
          parameter. Changes that will be updated to the Database are:&lt;br /&gt;
          'export_locations' and 'replica_state'.&lt;br /&gt;
      :raises Exception&lt;br /&gt;
          This can be any exception derived from BaseException. This is&lt;br /&gt;
          re-raised by the manager after some necessary cleanup. If the&lt;br /&gt;
          driver raises an exception during promotion, it is assumed&lt;br /&gt;
          that all of the replicas of the share are in an inconsistent&lt;br /&gt;
          state. Recovery is only possible through the periodic update&lt;br /&gt;
          call and/or administrator intervention to correct the 'status'&lt;br /&gt;
          of the affected replicas if they become healthy again.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      def update_replica_state(self, context, replica, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Update the replica_state of a replica.&lt;br /&gt;
        Drivers should fix replication relationships that were broken if&lt;br /&gt;
        possible inside this method.&lt;br /&gt;
        :param context:Current context&lt;br /&gt;
        :param replica: Dictionary of the replica being updated.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
             .. code::&lt;br /&gt;
            {&lt;br /&gt;
            'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
            'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'deleted': False,&lt;br /&gt;
            'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
            'status': 'available',&lt;br /&gt;
            'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'terminated_at': None,&lt;br /&gt;
            'replica_state': 'active',&lt;br /&gt;
            'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
            'export_locations': [&lt;br /&gt;
                models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
            ],&lt;br /&gt;
            'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
            }&lt;br /&gt;
        :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None&lt;br /&gt;
        :return: replica_state&lt;br /&gt;
            replica_state - a str value denoting the replica_state that the&lt;br /&gt;
            replica can have. Valid values are 'in_sync' and 'out_of_sync'&lt;br /&gt;
            or None (to leave the current replica_state unchanged).&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
==Manila Client==&lt;br /&gt;
    share-replica-create Creates a replica&lt;br /&gt;
    share-replica-delete Remove one or more share replicas.&lt;br /&gt;
    share-replica-list  List share replicas.&lt;br /&gt;
    share-replica-promote Promote replica to active replica.&lt;br /&gt;
    share-replica-show  Show details about a replica.&lt;br /&gt;
&lt;br /&gt;
==Example Conf==&lt;br /&gt;
[backend1]&lt;br /&gt;
replication_partners = backend2&lt;br /&gt;
[backend2]&lt;br /&gt;
replication_partners = backend1&lt;br /&gt;
&lt;br /&gt;
==First-Party Driver==&lt;br /&gt;
DR will require first-party driver support before it can be promoted from an experimental feature for two main reasons.&lt;br /&gt;
# A feature is not truly open if only a single vendor can develop it due to it only being supported by a proprietary driver. &lt;br /&gt;
# In order to ensure the quality of a feature, it must be testable in upstream gate.&lt;br /&gt;
&lt;br /&gt;
=FAQs=&lt;br /&gt;
# '''How do we deal with Network issues in multi-SVM replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If we choose to make replication a single-svm-only feature, the share-network API doesn't need to change. In order to support replication with share-networks, we also need to modify the share-network create API which allows creation of share networks with a table of AZ-to-subnet mappings. This approach allows us to keep a single share-network per share (with associated security service) while allowing the tenant to specify enough information that each share instance can be attached to the appropriate network in each AZ. Multi-AZ share networks would also be useful for non-replicated use cases.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we support Pool-level Replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Some vendors have suggested that certain backends can mirror groups of shares or whole pools more efficiently than individual shares. This design only addresses the mirroring of individual shares. In the future, we may allow allow replication of groups of shares, but only if those groups are contained within a single tenant and defined by the tenant.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''From where to where do we allow replication? Is it intra-cloud or inter-cloud? Do we allow replication to something that's not managed by Manila?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Intra-cloud. Replicating to something outside of Manila allows a bit more freedom, but with significantly less value, because there's practically nothing we can do to automate the failover/failback portion of a disaster. For use cases involving replication outside of Manila, we would need to involve other tools with more breadth/scope to manage the process.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Who configures the replication? The admin? The end user? The manila scheduler?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The end user. In the original design we presumed that the actual replication relationships should be hidden from the end user, but this doesn't match well with the concept of AZs that we are adding to Manila. If the users need to have control over which AZ the primary copy of their data lives in, then they also need to control where the other copies live. This means that the administrator's job is to ensure that for any share type that is replicated, it can be replicated from any AZ to any other AZ.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Is replication supported only intra-region or inter-region as well? How about intra-AZ vs inter-AZ?''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This design is for intra-region only. Inter-region replication is clearly a feature we want, but it would look pretty different from intra-region replication; this design does not cover that. Intra-AZ replication is supported, however inter-AZ replication is recommended as AZs should be perceived as failure domains.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Unanswered Questions=&lt;br /&gt;
# '''Is there no way to achieve non-disruptive failover?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(bswartz) I would love to find out that our initial intuition here is wrong, because it would change a lot of aspects of the design. It's worth spending time to brainstorm and research possibilities in this area. So far the most promising ideas involve:&lt;br /&gt;
#*Using VirtFS to mediate filesystem access and achieving non-disruptive failover that way&lt;br /&gt;
#*Using some kind of agent inside the guests to mediate file access&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Can a replica have a different share_type? There is a valid use case where a user would want to create a share replica on backend with different capabilities than the one the original share resides on. For instance, replicas might need to be on a less expensive backend. In that case, can the replica have a different share_type altogether?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;quot;Currently&amp;quot;, we inherit the share_type of the share and believe that replication has to be on symmetric terms, where both backends have similar capabilities.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''Can we allow the driver to restrict replication support between available backends? Backends may support replication to other compatible backends only. Hence, they must report some sort of information to the scheduler so that when creating a replica for an existing share, the scheduler would use that information to schedule the creation of the replica. What information should this be?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) We're investigating including 'driver_class_name' in a ReplicationFilter, including the possibility of backend reported configuration, 'replication_partners'.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How are access rules persisted across replicas/share instances?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#*Do all replicas have the same access rules applied? (gouthamr): This is Currently being pursued&lt;br /&gt;
#*Should access rules be applied only to &amp;quot;active&amp;quot; replicas?&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How does migration affect replicated shares?'''&lt;br /&gt;
#*(gouthamr)In the Tokyo summit, it was decided that we currently disallow migration of a share that has replicas. The replication relationships must be broken and reestablished after the migration is complete in order to migrate a share with replicas.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we need an API to initiate a sync? (resync or force-update)''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This is a great idea and one certain use case is during planned failovers. (gouthamr)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''How to recover from promotion failures?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) Currently, if some exception occurs at the driver level, the replicas are rendered useless. Should we provide escape hatches to avoid complete loss in case these are recoverable exceptions? The administrator has the ability to 'reset-state' and affect the 'status' of any replica. Currently, there exists no API to 'reset-replica-state' for a replica.&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
These examples assume that the replicas exist in different AZs.&lt;br /&gt;
&lt;br /&gt;
== Writable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=writeable&lt;br /&gt;
# Administrator creates a new share_type called foo&lt;br /&gt;
# Administrator sets replication_type=writeable extra spec on share type foo&lt;br /&gt;
# User creates new share of type foo in AZ b1&lt;br /&gt;
# Share is created with replication_type=writeable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to active (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 writes some data to the share, which is immediately visible to client1&lt;br /&gt;
&lt;br /&gt;
== Readable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=readable&lt;br /&gt;
# Administrator creates a new share_type called bar&lt;br /&gt;
# Administrator sets replication_type=readable extra spec on share type bar&lt;br /&gt;
# User creates new share of type bar in AZ b1&lt;br /&gt;
# Share is created with replication_type=readable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to in_sync (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 cannot write data to the share but continues to see updates&lt;br /&gt;
&lt;br /&gt;
== Failover/failback example ==&lt;br /&gt;
&lt;br /&gt;
(Continued from above)&lt;br /&gt;
# An outage occurs in AZ b1&lt;br /&gt;
# Administrator sends out a bulletin about the outage to his users &amp;quot;the power transformer in b1 turned to slag, it will be 12 hours before it can be replaced, please bear with us, yada yada&amp;quot;&lt;br /&gt;
# User notices that his application on client1 is no longer running, and investigates&lt;br /&gt;
# User finds out that client1 is gone, and reads a bulletin from the admin explaining why&lt;br /&gt;
# User notes that the b1 replica is his share is still active and the b2 replica is in_sync, while the state of the share is available&lt;br /&gt;
# User calls set active replica to AZ b2 on his share&lt;br /&gt;
# The share goes to state replication_change and access to the share is briefly lost on client2&lt;br /&gt;
# The state of replica b2 changes to active and the state of replica b1 changes to out_of_sync after Manila fails to contact the original primary. The state of the share changes back to available, and access is restored on client2&lt;br /&gt;
# User starts his application on client2, and the application recovers from an apparent crash, with a consistent copy of the application's data&lt;br /&gt;
# User application is back up and running, disaster is averted&lt;br /&gt;
# Eventually maintenance on the b1 AZ is completed, and all of the equipment is reactivated&lt;br /&gt;
# Administrator sends out a bulletin to his users about the outage ending &amp;quot;we replaced the transformer with a better one, everything is back online, thanks for your understanding, yada yada&amp;quot;&lt;br /&gt;
# Manila notices the out_of_sync replica is reachable and initiates a resync, bringing the b1 replica in_sync within a short time&lt;br /&gt;
# After some time, the users reads the bulletin and observes that his share is being replicated again. He decides to intentionally move back to b1.&lt;br /&gt;
# User gracefully shuts down his application, and flushes I/O&lt;br /&gt;
# User calls set active replica to AZ b1 on his share&lt;br /&gt;
# The share goes to state replication_change and no disruption is observed because the application is shut down&lt;br /&gt;
# The state of replica b1 changes to active and the state of replica b2 changes to in_sync after Manila reverses the replication again. The state of the share changes back to available&lt;br /&gt;
# User starts his application on client1, and the application starts cleanly, having been shut down gracefully&lt;br /&gt;
&lt;br /&gt;
=Implementation Progress=&lt;br /&gt;
===Core Work===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manila-share-replication Blueprint for Core API/Scheduler implementation]&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manilaclient-share-replication Blueprint for Client implementation]&lt;br /&gt;
&lt;br /&gt;
===Ex Driver Implementation===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/netapp-cdot-single-svm-replication Blueprint for cDOT Driver Implementation]&lt;br /&gt;
&lt;br /&gt;
=Older Design Pages=&lt;br /&gt;
* Replication Use Cases: https://wiki.openstack.org/wiki/Manila/Replication_Use_Cases&lt;br /&gt;
* Design Notes: https://wiki.openstack.org/wiki/Manila/Replication_Design_Notes&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_CI&amp;diff=100970</id>
		<title>ThirdPartySystems/NetApp CI</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_CI&amp;diff=100970"/>
				<updated>2016-01-12T15:15:17Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ThirdPartySystemInfo|name=NetApp CI&lt;br /&gt;
|account=netapp-ci&lt;br /&gt;
|contact= xdl-openstack-jenkins@netapp.com, andrew.kerr@netapp.com (akerr), alex.meade@netapp.com (ameade)&lt;br /&gt;
|intent=Test Openstack with NetApp Cinder and Manila drivers using storage arrays&lt;br /&gt;
|structure=Nodepool, Zuul, Jenkins, modified upstream components with local configuration&lt;br /&gt;
|method=Using Zuul to connect to Gerrit&lt;br /&gt;
|programs=Cinder, Manila&lt;br /&gt;
|status=Reporting on openstack/cinder and openstack/manila. System will be down January 22-29, 2016 due to Lab equipment moving.&lt;br /&gt;
|recheck=run-netapp-ci}}&lt;br /&gt;
'''Recheck trigger:''' &amp;quot;run-netapp-ci&amp;quot;&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_CI&amp;diff=100969</id>
		<title>ThirdPartySystems/NetApp CI</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_CI&amp;diff=100969"/>
				<updated>2016-01-12T15:13:32Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: Notice of downtime&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ThirdPartySystemInfo|name=NetApp CI&lt;br /&gt;
|account=netapp-ci&lt;br /&gt;
|contact= xdl-openstack-jenkins@netapp.com, andrew.kerr@netapp.com (akerr), alex.meade@netapp.com (ameade)&lt;br /&gt;
|intent=Test Openstack with NetApp Cinder and Manila drivers using storage arrays&lt;br /&gt;
|structure=Nodepool, Zuul, Jenkins, modified upstream components with local configuration&lt;br /&gt;
|method=Using Zuul to connect to Gerrit&lt;br /&gt;
|programs=Cinder, Manila&lt;br /&gt;
|status=Reporting on openstack/cinder and openstack/manila. System will be down the week of January 18, 2016 due to Lab equipment moving.&lt;br /&gt;
|recheck=run-netapp-ci}}&lt;br /&gt;
'''Recheck trigger:''' &amp;quot;run-netapp-ci&amp;quot;&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=99146</id>
		<title>Manila/design/manila-mitaka-data-replication</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=99146"/>
				<updated>2015-12-08T21:31:41Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Driver API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=Manila Disaster Recovery / Data Replication Design=&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Replicated shares will be implemented in Manila without adding any new services or any new drivers. The code for creating replicated shares and for adding/removing replicas and other replication-related operations will all go into the existing share drivers. The most significant change required to allow this will be that share drivers will be responsible for communicating with ALL storage controllers necessary to achieve any replication tasks, even if that involves sending commands to other storage controllers in other AZs.&lt;br /&gt;
&lt;br /&gt;
While we can't know how every storage controller works and how each vendor will implement replication, this approach should give driver writers all the flexibility needed to implement what they need with minimal added complexity in the Manila core. There are already examples of drivers reading config sections for other drivers when a operation requires communicating with 2 backends. The Manila Share Manager itself is expected to communicate all necessary backend details for share replicas that exist across AZs to a backend which it requests an operation upon.&lt;br /&gt;
&lt;br /&gt;
Intra-AZ replication is supported, but in an ideal solution, AZs should be perceived as failure domains. So this feature tends to shine in an inter-AZ replication use case. &lt;br /&gt;
&lt;br /&gt;
===Supported Replication Types===&lt;br /&gt;
There are 3 styles of DR that we would like to support in the long run:&lt;br /&gt;
&lt;br /&gt;
# writable - Amazon EFS-style synchronously replicated shares where all replicas are writable. Promotion it not supported and not needed.&lt;br /&gt;
# readable - Mirror-style replication with a primary (writable) copy and one or more secondary (read-only) copies which can become writable after a promotion of the secondary.&lt;br /&gt;
# dr - Generalized replication with secondary copies that are inaccessible until after a promotion of one of the secondary copies.&lt;br /&gt;
&lt;br /&gt;
===Replica States===&lt;br /&gt;
Each replica has a ''replica_state'' which has 4 possible values:&lt;br /&gt;
&lt;br /&gt;
# active - All writable replicas are active.&lt;br /&gt;
# in_sync - Passive replica which is up to date with the active replica, and can be promoted to active.&lt;br /&gt;
# out_of_sync - Passive replica which has gone out of date, or new replica that is not yet up to date.&lt;br /&gt;
# error - Either the scheduler failed to schedule this replica or some irrecoverable damage occurred during promotion of a non-active replica. Drivers may set the ''replica_state'' to ''error'' if some irrecoverable damage to the replica is discovered at any point during its existence. (through the periodic ''replica_state'' update)&lt;br /&gt;
[[File:Manila instance replication states.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New share state===&lt;br /&gt;
replication_change - New transient state triggered by a change of the active replica. Access to the share is cut off while in this state.&lt;br /&gt;
&lt;br /&gt;
===Promotion===&lt;br /&gt;
For '''readable''' and '''dr''' styles, we refer to the task of switching a non-active replica with the '''active''' replica as '''promotion'''. For the '''writable''' style of replication, '''promotion''' does not make sense since all replicas are '''active''' (writable) at all given points of time. Promotion of replicas with '''replica_state''' set to '''out_of_sync''' or '''error''' may be unsupported by the backend. However, we would like to allow the action as an administrator feature and such an attempt may be honored by backends if possible. &lt;br /&gt;
&lt;br /&gt;
When multiple replicas exist, multiple replication relationships between shares may need to be redefined at the backend. If the driver fails at this stage, the replicas may be left at an inconsistent state. The manager will set all replica instances to have '''replica_state''' and '''status''' to '''error'''. Recovery from this stage would require administrator intervention.&lt;br /&gt;
&lt;br /&gt;
==User Workflows==&lt;br /&gt;
====Creating a share supporting replication====&lt;br /&gt;
* Administrators can create a share type with extra-spec ''replication_type'', specifying the style of replication the backend supports.&lt;br /&gt;
* Users can use the share type to create a new share that allows/supports replication.&lt;br /&gt;
* A replicated share always starts out with one replica instance, the share itself. This should not be confused as the share having a replica already. The user can verify if the share has any replicas by requesting the details of the share.&lt;br /&gt;
&lt;br /&gt;
====Creating a replica====&lt;br /&gt;
* POST to /share-replicas&lt;br /&gt;
User has to specify the share name/id of the share that is supposed to be replicated, an availability zone for the replica to exist in and optionally a share_network_id.&lt;br /&gt;
According to existing design, replicas of a share cannot exist in the same availability zone as the share itself.&lt;br /&gt;
* A newly created share_replica starts out in ''out_of_sync'' state and might transition to ''in_sync'' state when the driver reports this state.&lt;br /&gt;
&lt;br /&gt;
====Listing and showing replicas====&lt;br /&gt;
* GET from /share-replicas&lt;br /&gt;
User can list all replicas and verify their ''status'' and ''replica_state''.&lt;br /&gt;
* GET from /share-replicas?share_id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
User can list replicas for a particular share.&lt;br /&gt;
* GET from /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
User can view details of a replica.&lt;br /&gt;
&lt;br /&gt;
====Promoting a non-active replica====&lt;br /&gt;
* POST to /share-replicas/action with body {'promote': None}&lt;br /&gt;
For replication types that permit promotion, the user can promote a replica with ''in_sync'' replica_state to ''active'' replica_state by initiating the ''promote_replica'' call.&lt;br /&gt;
* Only administrators can attempt promoting replicas with replica_state ''error'' or ''out_of_sync''.&lt;br /&gt;
&lt;br /&gt;
====Deleting Replicas====&lt;br /&gt;
* DELETE to /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
The user can delete a replica. The last ''active'' replica cannot be deleted using this ''delete_replica'' call.&lt;br /&gt;
&lt;br /&gt;
==System Workflows==&lt;br /&gt;
* Creating a share that supports replication&lt;br /&gt;
** Same process as creating a new share.&lt;br /&gt;
** The ''replication_type'' extra-spec from the share-type is copied over to the share''s data on the DB.&lt;br /&gt;
** Scheduler uses the ''replication_type'' extra-spec to filter available hosts and schedule the share on an appropriate backend that supports that specific style of ''replication_type''.&lt;br /&gt;
&lt;br /&gt;
* Creating a replica:&lt;br /&gt;
** Create a share instance on the database.&lt;br /&gt;
** Update the share instance ''replica_state'' to ''out_of_sync''.&lt;br /&gt;
** Cast a call to the scheduler to find an appropriate host to schedule the replica on.&lt;br /&gt;
** In the scheduler, find weighted host for the replica.&lt;br /&gt;
*** If host cannot be chosen, update the replica's ''status'' and ''replica_state'' on the Database to ''error''. Throw an exception.&lt;br /&gt;
** Cast the create_share_replica call to the driver based on the weighted host selection.&lt;br /&gt;
** Prior to invoking the driver's call, collate information regarding existing ''active'' replica instance, existing share access rules and the replica's share_server, pass these to the driver while invoking ''create_replica''.&lt;br /&gt;
** The driver may return ''export_locations'' and ''replica_state''. If they are returned, the database is updated with these values.&lt;br /&gt;
** If the ''replication_type'' is ''writable'', the driver MUST return the ''replica_state'' set to ''active''.&lt;br /&gt;
** All the access rules for the new replica are set to ''active'' state on the database.&lt;br /&gt;
** The driver may throw an exception, update the ''status'' and ''replica_state'' of the replica to ''error''.&lt;br /&gt;
&lt;br /&gt;
* Listing/showing shares:&lt;br /&gt;
** For shares that support replication, the result of listing/showing the share will have new fields, ''replication_type'': denoting the replication style supported and ''has_replicas'' to denote if the share has replicas.&lt;br /&gt;
** For replicated shares, the primary instance for the share must be preferred among those replicas that have a status ''replication_change'' or among those that have a replica_state set to ''active''.&lt;br /&gt;
&lt;br /&gt;
* Listing replicas&lt;br /&gt;
** For listing, Grab share instances from the database that have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** If share_id is provided, grab only share instances that belong to that share and have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** Limits and offsets must be respected on the list calls.&lt;br /&gt;
&lt;br /&gt;
* Promoting a non-active replica:&lt;br /&gt;
** If replica is already active, do nothing.&lt;br /&gt;
** Update the ''status'' of the replica being promoted to ''replication_change''.&lt;br /&gt;
** Grab all available replicas and invoke the appropriate driver''s promote_replica call by passing the available replicas and the new replica.&lt;br /&gt;
** If the driver throws an exception at this stage, there is a good chance that the replicas are somehow altered on the backend. Loop through the replicas and set their ''replica_state''s to ''error'' and leave the ''status'' unchanged. Also set the ''status'' of the replica that failed to promote to ''available'' as before this operation. The backend may choose to update the actual replica_state during the replica monitoring call.&lt;br /&gt;
** The driver may return an updated list of replicas. Update the ''export_locations'' and ''replica_state''s to the database.&lt;br /&gt;
** The ''status'' of the replica that was promoted should return to ''available'' from ''replication_change''.&lt;br /&gt;
&lt;br /&gt;
* Periodic replica update:&lt;br /&gt;
** The share manager implements a looping call with default interval of 5 minutes to query from each driver and each backend the ''replica_state'' of all non-active replicas that are associated with them.&lt;br /&gt;
** The driver is allowed to set the ''replica_state'' to ''in_sync'', ''out_of_sync'', and in exceptional cases, ''error''.&lt;br /&gt;
** If the driver sets the ''replica_state'' of a replica to ''error'', it is assumed that some irrecoverable damage has occured to the replica instance. The ''status'' of the replica instance must be set to ''error'' as well.&lt;br /&gt;
&lt;br /&gt;
* Deleting a share replica&lt;br /&gt;
** If the replica had no host, it is simply removed from the database.&lt;br /&gt;
** The ''status'' of the replica is set to ''deleting'' on the database and the appropriate driver method is called to delete the replica.&lt;br /&gt;
** If the driver fails to delete the replica, the ''status'' of the replica is updated to ''error_deleting'' on the database.&lt;br /&gt;
** If the driver returns without errors, the replica instance is removed from the database.&lt;br /&gt;
&lt;br /&gt;
==Scheduler Impact==&lt;br /&gt;
* The host_manager must update the ''replication_type'' capability from the backend. The backends must report this capability at the host/pool level.&lt;br /&gt;
* The filter_scheduler must then match the ''replication_type'' capability with the capability that the replication share_type demands.&lt;br /&gt;
* The ''replication_type'' must be one of the styles mentioned [[#Supported Replication Styles|above]].&lt;br /&gt;
&lt;br /&gt;
==DB Impact==&lt;br /&gt;
* Share Export Locations:&lt;br /&gt;
Preferred export locations will only be from the instances with ''replica_state'' set to ''active''.&lt;br /&gt;
  def export_locations(self):&lt;br /&gt;
      # TODO(gouthamr): Return AZ specific export locations for replicated&lt;br /&gt;
      #  shares&lt;br /&gt;
      # NOTE(gouthamr): For a replicated share, export locations of the&lt;br /&gt;
      # 'active' instances are taken, if 'available'.&lt;br /&gt;
      all_export_locations = []&lt;br /&gt;
      select_instances = list(filter(&lt;br /&gt;
          lambda x: x['replica_state'] == constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
          self.instances)) or self.instances&lt;br /&gt;
      for instance in select_instances:&lt;br /&gt;
          if instance['status'] == constants.STATUS_AVAILABLE:&lt;br /&gt;
              for export_location in instance.export_locations:&lt;br /&gt;
                  all_export_locations.append(export_location['path'])&lt;br /&gt;
    return all_export_locations&lt;br /&gt;
&lt;br /&gt;
* Share Instance:&lt;br /&gt;
Preferred instance will be an instance with ''status'' set to ''replication_change'' or any instance with ''status'' set to ''available'' and ''replica_state'' set to ''active''.&lt;br /&gt;
  def instance(self):&lt;br /&gt;
   # NOTE(gouthamr): The order of preference: status 'replication_change',&lt;br /&gt;
   # followed  by 'available' and 'creating'. If replicated share and&lt;br /&gt;
   # not undergoing a 'replication_change', only 'active' instances are&lt;br /&gt;
   # preferred.&lt;br /&gt;
   result = None&lt;br /&gt;
   if len(self.instances) &amp;gt; 0:&lt;br /&gt;
       order = [constants.STATUS_REPLICATION_CHANGE,&lt;br /&gt;
                constants.STATUS_AVAILABLE, constants.STATUS_CREATING]&lt;br /&gt;
       other_statuses = ([x['status'] for x in self.instances&lt;br /&gt;
                          if x['status'] not in order])&lt;br /&gt;
       order.extend(other_statuses)&lt;br /&gt;
       sorted_instances = sorted(&lt;br /&gt;
           self.instances, key=lambda x: order.index(x['status']))&lt;br /&gt;
       select_instances = sorted_instances&lt;br /&gt;
       if (select_instances[0]['status'] !=&lt;br /&gt;
               constants.STATUS_REPLICATION_CHANGE):&lt;br /&gt;
           select_instances = (&lt;br /&gt;
               list(filter(lambda x: x['replica_state'] ==&lt;br /&gt;
                           constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
                           sorted_instances)) or sorted_instances&lt;br /&gt;
           )&lt;br /&gt;
       result = select_instances[0]&lt;br /&gt;
   return result&lt;br /&gt;
&lt;br /&gt;
* New field on Share:&lt;br /&gt;
  replication_type = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
* New field on ShareInstance&lt;br /&gt;
  replica_state = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API Design==&lt;br /&gt;
  GET /share-replicas/&lt;br /&gt;
  GET /share-replicas?share-id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
  GET /share-replicas/&amp;lt;replica_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  POST /share-replicas/&amp;lt;share-id&amp;gt;&lt;br /&gt;
  Body:&lt;br /&gt;
  {&lt;br /&gt;
    'share_replica':&lt;br /&gt;
    {&lt;br /&gt;
      'availability_zone':&amp;lt;availability_zone_id&amp;gt;,&lt;br /&gt;
      'share_id':&amp;lt;share_id&amp;gt;,&lt;br /&gt;
      'share_network_id':&amp;lt;share_network_id&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  POST /share-replicas/&amp;lt;replica-id&amp;gt;/action&lt;br /&gt;
  Body:&lt;br /&gt;
  {'os-promote_replica': null}&lt;br /&gt;
&lt;br /&gt;
  DELETE /share-replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
&lt;br /&gt;
policy.json - All replication group policies should default to the default policy&lt;br /&gt;
    &amp;quot;share_replica:get_all&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:show&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:create&amp;quot; : &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:delete&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:promote&amp;quot;: &amp;quot;rule:default&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
Only a single replication driver method will be called at a time for a given share as they are locked by share id. Drivers should avoid raising errors to the manager for any of these methods. If the driver hits an issue it should attempt to return the correct model updates with the correct error states set to represent the actual state of the resources. A driver raising an exception will result in all replicas in the error status with the replica_state unchanged.&lt;br /&gt;
&lt;br /&gt;
  def create_replica(self, context, active_replica, new_replica,&lt;br /&gt;
                   access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Replicate the active replica to a new replica on this backend.&lt;br /&gt;
      :param context: Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              &amp;lt;models.ShareInstanceExportLocations&amp;gt;._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param new_replica: The share replica dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'out_of_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica being created.&lt;br /&gt;
      :return: (export_locations, replica_state)&lt;br /&gt;
      export_locations is a list of paths and replica_state is one of&lt;br /&gt;
      active, in-sync, out-of-sync or error.&lt;br /&gt;
      A backend supporting 'writable' type replication should return&lt;br /&gt;
      'active' as the replica_state.&lt;br /&gt;
      Export locations should be in the same format as returned by a&lt;br /&gt;
      share_create. This list may be empty or None.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
          .. code::&lt;br /&gt;
              [{'id': 'uuid', 'export_locations': ['export_path']}]&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def delete_replica(self, context, active_replica, replica,&lt;br /&gt;
                   share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Delete a replica.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param replica: Dictionary of the share replica being deleted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be deleted.&lt;br /&gt;
      :return: None.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def promote_replica(self, context, replica_list, replica, access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Promote a replica to 'active' replica state.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param replica_list: List of all replicas for a particular share.&lt;br /&gt;
      This list also contains the replica to be promoted. The 'active'&lt;br /&gt;
      replica will have its 'replica_state' attr set to 'active'.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          [&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'active',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              ...&lt;br /&gt;
          ]&lt;br /&gt;
      :param replica: Dictionary of the replica to be promoted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be promoted.&lt;br /&gt;
      :return: updated_replica_list or None&lt;br /&gt;
          The driver can return the updated list as in the request&lt;br /&gt;
          parameter. Changes that will be updated to the Database are:&lt;br /&gt;
          'export_locations' and 'replica_state'.&lt;br /&gt;
      :raises Exception&lt;br /&gt;
          This can be any exception derived from BaseException. This is&lt;br /&gt;
          re-raised by the manager after some necessary cleanup. If the&lt;br /&gt;
          driver raises an exception during promotion, it is assumed&lt;br /&gt;
          that all of the replicas of the share are in an inconsistent&lt;br /&gt;
          state. Recovery is only possible through the periodic update&lt;br /&gt;
          call and/or administrator intervention to correct the 'status'&lt;br /&gt;
          of the affected replicas if they become healthy again.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      def update_replica_state(self, context, replica, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Update the replica_state of a replica.&lt;br /&gt;
        Drivers should fix replication relationships that were broken if&lt;br /&gt;
        possible inside this method.&lt;br /&gt;
        :param context:Current context&lt;br /&gt;
        :param replica: Dictionary of the replica being updated.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
             .. code::&lt;br /&gt;
            {&lt;br /&gt;
            'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
            'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'deleted': False,&lt;br /&gt;
            'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
            'status': 'available',&lt;br /&gt;
            'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'terminated_at': None,&lt;br /&gt;
            'replica_state': 'active',&lt;br /&gt;
            'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
            'export_locations': [&lt;br /&gt;
                models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
            ],&lt;br /&gt;
            'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
            }&lt;br /&gt;
        :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None&lt;br /&gt;
        :return: replica_state&lt;br /&gt;
            replica_state - a str value denoting the replica_state that the&lt;br /&gt;
            replica can have. Valid values are 'in_sync' and 'out_of_sync'&lt;br /&gt;
            or None (to leave the current replica_state unchanged).&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
==Manila Client==&lt;br /&gt;
    share-replica-create Creates a replica&lt;br /&gt;
    share-replica-delete Remove one or more share replicas.&lt;br /&gt;
    share-replica-list  List share replicas.&lt;br /&gt;
    share-replica-promote Promote replica to active replica.&lt;br /&gt;
    share-replica-show  Show details about a replica.&lt;br /&gt;
&lt;br /&gt;
==First-Party Driver==&lt;br /&gt;
DR will require first-party driver support before it can be promoted from an experimental feature for two main reasons. 1. A feature is not truly open if only a single vendor can develop it due to it only being supported by a proprietary driver. 2. In order to ensure the quality of a feature, it must be testable in upstream gate.&lt;br /&gt;
&lt;br /&gt;
=FAQs=&lt;br /&gt;
# '''How do we deal with Network issues in multi-SVM replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If we choose to make replication a single-svm-only feature, the share-network API doesn't need to change. In order to support replication with share-networks, we also need to modify the share-network create API which allows creation of share networks with a table of AZ-to-subnet mappings. This approach allows us to keep a single share-network per share (with associated security service) while allowing the tenant to specify enough information that each share instance can be attached to the appropriate network in each AZ. Multi-AZ share networks would also be useful for non-replicated use cases.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we support Pool-level Replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Some vendors have suggested that certain backends can mirror groups of shares or whole pools more efficiently than individual shares. This design only addresses the mirroring of individual shares. In the future, we may allow allow replication of groups of shares, but only if those groups are contained within a single tenant and defined by the tenant.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''From where to where do we allow replication? Is it intra-cloud or inter-cloud? Do we allow replication to something that's not managed by Manila?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Intra-cloud. Replicating to something outside of Manila allows a bit more freedom, but with significantly less value, because there's practically nothing we can do to automate the failover/failback portion of a disaster. For use cases involving replication outside of Manila, we would need to involve other tools with more breadth/scope to manage the process.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Who configures the replication? The admin? The end user? The manila scheduler?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The end user. In the original design we presumed that the actual replication relationships should be hidden from the end user, but this doesn't match well with the concept of AZs that we are adding to Manila. If the users need to have control over which AZ the primary copy of their data lives in, then they also need to control where the other copies live. This means that the administrator's job is to ensure that for any share type that is replicated, it can be replicated from any AZ to any other AZ.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Is replication supported only intra-region or inter-region as well? How about intra-AZ vs inter-AZ?''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This design is for intra-region only. Inter-region replication is clearly a feature we want, but it would look pretty different from intra-region replication; this design does not cover that. Intra-AZ replication is supported, however inter-AZ replication is recommended as AZs should be perceived as failure domains.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Unanswered Questions=&lt;br /&gt;
# '''Is there no way to achieve non-disruptive failover?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(bswartz) I would love to find out that our initial intuition here is wrong, because it would change a lot of aspects of the design. It's worth spending time to brainstorm and research possibilities in this area. So far the most promising ideas involve:&lt;br /&gt;
#*Using VirtFS to mediate filesystem access and achieving non-disruptive failover that way&lt;br /&gt;
#*Using some kind of agent inside the guests to mediate file access&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Can a replica have a different share_type? There is a valid use case where a user would want to create a share replica on backend with different capabilities than the one the original share resides on. For instance, replicas might need to be on a less expensive backend. In that case, can the replica have a different share_type altogether?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;quot;Currently&amp;quot;, we inherit the share_type of the share and believe that replication has to be on symmetric terms, where both backends have similar capabilities.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''Can we allow the driver to restrict replication support between available backends? Backends may support replication to other compatible backends only. Hence, they must report some sort of information to the scheduler so that when creating a replica for an existing share, the scheduler would use that information to schedule the creation of the replica. What information should this be?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) We're investigating including 'driver_class_name' in a ReplicationFilter, including the possibility of backend reported configuration, 'replication_partners'.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How are access rules persisted across replicas/share instances?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#*Do all replicas have the same access rules applied? (gouthamr): This is Currently being pursued&lt;br /&gt;
#*Should access rules be applied only to &amp;quot;active&amp;quot; replicas?&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How does migration affect replicated shares?'''&lt;br /&gt;
#*(gouthamr)In the Tokyo summit, it was decided that we currently disallow migration of a share that has replicas. The replication relationships must be broken and reestablished after the migration is complete in order to migrate a share with replicas.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we need an API to initiate a sync? (resync or force-update)''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This is a great idea and one certain use case is during planned failovers. (gouthamr)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''How to recover from promotion failures?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) Currently, if some exception occurs at the driver level, the replicas are rendered useless. Should we provide escape hatches to avoid complete loss in case these are recoverable exceptions? The administrator has the ability to 'reset-state' and affect the 'status' of any replica. Currently, there exists no API to 'reset-replica-state' for a replica.&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
These examples assume that the replicas exist in different AZs.&lt;br /&gt;
&lt;br /&gt;
== Writable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=writeable&lt;br /&gt;
# Administrator creates a new share_type called foo&lt;br /&gt;
# Administrator sets replication_type=writeable extra spec on share type foo&lt;br /&gt;
# User creates new share of type foo in AZ b1&lt;br /&gt;
# Share is created with replication_type=writeable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to active (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 writes some data to the share, which is immediately visible to client1&lt;br /&gt;
&lt;br /&gt;
== Readable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=readable&lt;br /&gt;
# Administrator creates a new share_type called bar&lt;br /&gt;
# Administrator sets replication_type=readable extra spec on share type bar&lt;br /&gt;
# User creates new share of type bar in AZ b1&lt;br /&gt;
# Share is created with replication_type=readable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to in_sync (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 cannot write data to the share but continues to see updates&lt;br /&gt;
&lt;br /&gt;
== Failover/failback example ==&lt;br /&gt;
&lt;br /&gt;
(Continued from above)&lt;br /&gt;
# An outage occurs in AZ b1&lt;br /&gt;
# Administrator sends out a bulletin about the outage to his users &amp;quot;the power transformer in b1 turned to slag, it will be 12 hours before it can be replaced, please bear with us, yada yada&amp;quot;&lt;br /&gt;
# User notices that his application on client1 is no longer running, and investigates&lt;br /&gt;
# User finds out that client1 is gone, and reads a bulletin from the admin explaining why&lt;br /&gt;
# User notes that the b1 replica is his share is still active and the b2 replica is in_sync, while the state of the share is available&lt;br /&gt;
# User calls set active replica to AZ b2 on his share&lt;br /&gt;
# The share goes to state replication_change and access to the share is briefly lost on client2&lt;br /&gt;
# The state of replica b2 changes to active and the state of replica b1 changes to out_of_sync after Manila fails to contact the original primary. The state of the share changes back to available, and access is restored on client2&lt;br /&gt;
# User starts his application on client2, and the application recovers from an apparent crash, with a consistent copy of the application's data&lt;br /&gt;
# User application is back up and running, disaster is averted&lt;br /&gt;
# Eventually maintenance on the b1 AZ is completed, and all of the equipment is reactivated&lt;br /&gt;
# Administrator sends out a bulletin to his users about the outage ending &amp;quot;we replaced the transformer with a better one, everything is back online, thanks for your understanding, yada yada&amp;quot;&lt;br /&gt;
# Manila notices the out_of_sync replica is reachable and initiates a resync, bringing the b1 replica in_sync within a short time&lt;br /&gt;
# After some time, the users reads the bulletin and observes that his share is being replicated again. He decides to intentionally move back to b1.&lt;br /&gt;
# User gracefully shuts down his application, and flushes I/O&lt;br /&gt;
# User calls set active replica to AZ b1 on his share&lt;br /&gt;
# The share goes to state replication_change and no disruption is observed because the application is shut down&lt;br /&gt;
# The state of replica b1 changes to active and the state of replica b2 changes to in_sync after Manila reverses the replication again. The state of the share changes back to available&lt;br /&gt;
# User starts his application on client1, and the application starts cleanly, having been shut down gracefully&lt;br /&gt;
&lt;br /&gt;
=Implementation Progress=&lt;br /&gt;
===Core Work===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manila-share-replication Blueprint for Core API/Scheduler implementation]&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manilaclient-share-replication Blueprint for Client implementation]&lt;br /&gt;
&lt;br /&gt;
===Ex Driver Implementation===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/netapp-cdot-single-svm-replication Blueprint for cDOT Driver Implementation]&lt;br /&gt;
&lt;br /&gt;
=Older Design Pages=&lt;br /&gt;
* Replication Use Cases: https://wiki.openstack.org/wiki/Manila/Replication_Use_Cases&lt;br /&gt;
* Design Notes: https://wiki.openstack.org/wiki/Manila/Replication_Design_Notes&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=99029</id>
		<title>Manila/design/manila-mitaka-data-replication</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=99029"/>
				<updated>2015-12-07T19:08:26Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Manila Disaster Recovery / Data Replication Design */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=Manila Disaster Recovery / Data Replication Design=&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Replicated shares will be implemented in Manila without adding any new services or any new drivers. The code for creating replicated shares and for adding/removing replicas and other replication-related operations will all go into the existing share drivers. The most significant change required to allow this will be that share drivers will be responsible for communicating with ALL storage controllers necessary to achieve any replication tasks, even if that involves sending commands to other storage controllers in other AZs.&lt;br /&gt;
&lt;br /&gt;
While we can't know how every storage controller works and how each vendor will implement replication, this approach should give driver writers all the flexibility needed to implement what they need with minimal added complexity in the Manila core. There are already examples of drivers reading config sections for other drivers when a operation requires communicating with 2 backends. The Manila Share Manager itself is expected to communicate all necessary backend details for share replicas that exist across AZs to a backend which it requests an operation upon.&lt;br /&gt;
&lt;br /&gt;
Intra-AZ replication is supported, but in an ideal solution, AZs should be perceived as failure domains. So this feature tends to shine in an inter-AZ replication use case. &lt;br /&gt;
&lt;br /&gt;
===Supported Replication Types===&lt;br /&gt;
There are 3 styles of DR that we would like to support in the long run:&lt;br /&gt;
&lt;br /&gt;
# writable - Amazon EFS-style synchronously replicated shares where all replicas are writable. Promotion it not supported and not needed.&lt;br /&gt;
# readable - Mirror-style replication with a primary (writable) copy and one or more secondary (read-only) copies which can become writable after a promotion of the secondary.&lt;br /&gt;
# dr - Generalized replication with secondary copies that are inaccessible until after a promotion of one of the secondary copies.&lt;br /&gt;
&lt;br /&gt;
===Replica States===&lt;br /&gt;
Each replica has a ''replica_state'' which has 4 possible values:&lt;br /&gt;
&lt;br /&gt;
# active - All writable replicas are active.&lt;br /&gt;
# in_sync - Passive replica which is up to date with the active replica, and can be promoted to active.&lt;br /&gt;
# out_of_sync - Passive replica which has gone out of date, or new replica that is not yet up to date.&lt;br /&gt;
# error - Either the scheduler failed to schedule this replica or some irrecoverable damage occurred during promotion of a non-active replica. Drivers may set the ''replica_state'' to ''error'' if some irrecoverable damage to the replica is discovered at any point during its existence. (through the periodic ''replica_state'' update)&lt;br /&gt;
[[File:Manila instance replication states.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New share state===&lt;br /&gt;
replication_change - New transient state triggered by a change of the active replica. Access to the share is cut off while in this state.&lt;br /&gt;
&lt;br /&gt;
===Promotion===&lt;br /&gt;
For '''readable''' and '''dr''' styles, we refer to the task of switching a non-active replica with the '''active''' replica as '''promotion'''. For the '''writable''' style of replication, '''promotion''' does not make sense since all replicas are '''active''' (writable) at all given points of time. Promotion of replicas with '''replica_state''' set to '''out_of_sync''' or '''error''' may be unsupported by the backend. However, we would like to allow the action as an administrator feature and such an attempt may be honored by backends if possible. &lt;br /&gt;
&lt;br /&gt;
When multiple replicas exist, multiple replication relationships between shares may need to be redefined at the backend. If the driver fails at this stage, the replicas may be left at an inconsistent state. The manager will set all replica instances to have '''replica_state''' and '''status''' to '''error'''. Recovery from this stage would require administrator intervention.&lt;br /&gt;
&lt;br /&gt;
==User Workflows==&lt;br /&gt;
====Creating a share supporting replication====&lt;br /&gt;
* Administrators can create a share type with extra-spec ''replication_type'', specifying the style of replication the backend supports.&lt;br /&gt;
* Users can use the share type to create a new share that allows/supports replication.&lt;br /&gt;
* A replicated share always starts out with one replica instance, the share itself. This should not be confused as the share having a replica already. The user can verify if the share has any replicas by requesting the details of the share.&lt;br /&gt;
&lt;br /&gt;
====Creating a replica====&lt;br /&gt;
* POST to /share-replicas&lt;br /&gt;
User has to specify the share name/id of the share that is supposed to be replicated, an availability zone for the replica to exist in and optionally a share_network_id.&lt;br /&gt;
According to existing design, replicas of a share cannot exist in the same availability zone as the share itself.&lt;br /&gt;
* A newly created share_replica starts out in ''out_of_sync'' state and might transition to ''in_sync'' state when the driver reports this state.&lt;br /&gt;
&lt;br /&gt;
====Listing and showing replicas====&lt;br /&gt;
* GET from /share-replicas&lt;br /&gt;
User can list all replicas and verify their ''status'' and ''replica_state''.&lt;br /&gt;
* GET from /share-replicas?share_id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
User can list replicas for a particular share.&lt;br /&gt;
* GET from /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
User can view details of a replica.&lt;br /&gt;
&lt;br /&gt;
====Promoting a non-active replica====&lt;br /&gt;
* POST to /share-replicas/action with body {'promote': None}&lt;br /&gt;
For replication types that permit promotion, the user can promote a replica with ''in_sync'' replica_state to ''active'' replica_state by initiating the ''promote_replica'' call.&lt;br /&gt;
* Only administrators can attempt promoting replicas with replica_state ''error'' or ''out_of_sync''.&lt;br /&gt;
&lt;br /&gt;
====Deleting Replicas====&lt;br /&gt;
* DELETE to /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
The user can delete a replica. The last ''active'' replica cannot be deleted using this ''delete_replica'' call.&lt;br /&gt;
&lt;br /&gt;
==System Workflows==&lt;br /&gt;
* Creating a share that supports replication&lt;br /&gt;
** Same process as creating a new share.&lt;br /&gt;
** The ''replication_type'' extra-spec from the share-type is copied over to the share''s data on the DB.&lt;br /&gt;
** Scheduler uses the ''replication_type'' extra-spec to filter available hosts and schedule the share on an appropriate backend that supports that specific style of ''replication_type''.&lt;br /&gt;
&lt;br /&gt;
* Creating a replica:&lt;br /&gt;
** Create a share instance on the database.&lt;br /&gt;
** Update the share instance ''replica_state'' to ''out_of_sync''.&lt;br /&gt;
** Cast a call to the scheduler to find an appropriate host to schedule the replica on.&lt;br /&gt;
** In the scheduler, find weighted host for the replica.&lt;br /&gt;
*** If host cannot be chosen, update the replica's ''status'' and ''replica_state'' on the Database to ''error''. Throw an exception.&lt;br /&gt;
** Cast the create_share_replica call to the driver based on the weighted host selection.&lt;br /&gt;
** Prior to invoking the driver's call, collate information regarding existing ''active'' replica instance, existing share access rules and the replica's share_server, pass these to the driver while invoking ''create_replica''.&lt;br /&gt;
** The driver may return ''export_locations'' and ''replica_state''. If they are returned, the database is updated with these values.&lt;br /&gt;
** If the ''replication_type'' is ''writable'', the driver MUST return the ''replica_state'' set to ''active''.&lt;br /&gt;
** All the access rules for the new replica are set to ''active'' state on the database.&lt;br /&gt;
** The driver may throw an exception, update the ''status'' and ''replica_state'' of the replica to ''error''.&lt;br /&gt;
&lt;br /&gt;
* Listing/showing shares:&lt;br /&gt;
** For shares that support replication, the result of listing/showing the share will have new fields, ''replication_type'': denoting the replication style supported and ''has_replicas'' to denote if the share has replicas.&lt;br /&gt;
** For replicated shares, the primary instance for the share must be preferred among those replicas that have a status ''replication_change'' or among those that have a replica_state set to ''active''.&lt;br /&gt;
&lt;br /&gt;
* Listing replicas&lt;br /&gt;
** For listing, Grab share instances from the database that have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** If share_id is provided, grab only share instances that belong to that share and have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** Limits and offsets must be respected on the list calls.&lt;br /&gt;
&lt;br /&gt;
* Promoting a non-active replica:&lt;br /&gt;
** If replica is already active, do nothing.&lt;br /&gt;
** Update the ''status'' of the replica being promoted to ''replication_change''.&lt;br /&gt;
** Grab all available replicas and invoke the appropriate driver''s promote_replica call by passing the available replicas and the new replica.&lt;br /&gt;
** If the driver throws an exception at this stage, there is a good chance that the replicas are somehow altered on the backend. Loop through the replicas and set their ''replica_state''s to ''error'' and leave the ''status'' unchanged. Also set the ''status'' of the replica that failed to promote to ''available'' as before this operation. The backend may choose to update the actual replica_state during the replica monitoring call.&lt;br /&gt;
** The driver may return an updated list of replicas. Update the ''export_locations'' and ''replica_state''s to the database.&lt;br /&gt;
** The ''status'' of the replica that was promoted should return to ''available'' from ''replication_change''.&lt;br /&gt;
&lt;br /&gt;
* Periodic replica update:&lt;br /&gt;
** The share manager implements a looping call with default interval of 5 minutes to query from each driver and each backend the ''replica_state'' of all non-active replicas that are associated with them.&lt;br /&gt;
** The driver is allowed to set the ''replica_state'' to ''in_sync'', ''out_of_sync'', and in exceptional cases, ''error''.&lt;br /&gt;
** If the driver sets the ''replica_state'' of a replica to ''error'', it is assumed that some irrecoverable damage has occured to the replica instance. The ''status'' of the replica instance must be set to ''error'' as well.&lt;br /&gt;
&lt;br /&gt;
* Deleting a share replica&lt;br /&gt;
** If the replica had no host, it is simply removed from the database.&lt;br /&gt;
** The ''status'' of the replica is set to ''deleting'' on the database and the appropriate driver method is called to delete the replica.&lt;br /&gt;
** If the driver fails to delete the replica, the ''status'' of the replica is updated to ''error_deleting'' on the database.&lt;br /&gt;
** If the driver returns without errors, the replica instance is removed from the database.&lt;br /&gt;
&lt;br /&gt;
==Scheduler Impact==&lt;br /&gt;
* The host_manager must update the ''replication_type'' capability from the backend. The backends must report this capability at the host/pool level.&lt;br /&gt;
* The filter_scheduler must then match the ''replication_type'' capability with the capability that the replication share_type demands.&lt;br /&gt;
* The ''replication_type'' must be one of the styles mentioned [[#Supported Replication Styles|above]].&lt;br /&gt;
&lt;br /&gt;
==DB Impact==&lt;br /&gt;
* Share Export Locations:&lt;br /&gt;
Preferred export locations will only be from the instances with ''replica_state'' set to ''active''.&lt;br /&gt;
  def export_locations(self):&lt;br /&gt;
      # TODO(gouthamr): Return AZ specific export locations for replicated&lt;br /&gt;
      #  shares&lt;br /&gt;
      # NOTE(gouthamr): For a replicated share, export locations of the&lt;br /&gt;
      # 'active' instances are taken, if 'available'.&lt;br /&gt;
      all_export_locations = []&lt;br /&gt;
      select_instances = list(filter(&lt;br /&gt;
          lambda x: x['replica_state'] == constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
          self.instances)) or self.instances&lt;br /&gt;
      for instance in select_instances:&lt;br /&gt;
          if instance['status'] == constants.STATUS_AVAILABLE:&lt;br /&gt;
              for export_location in instance.export_locations:&lt;br /&gt;
                  all_export_locations.append(export_location['path'])&lt;br /&gt;
    return all_export_locations&lt;br /&gt;
&lt;br /&gt;
* Share Instance:&lt;br /&gt;
Preferred instance will be an instance with ''status'' set to ''replication_change'' or any instance with ''status'' set to ''available'' and ''replica_state'' set to ''active''.&lt;br /&gt;
  def instance(self):&lt;br /&gt;
   # NOTE(gouthamr): The order of preference: status 'replication_change',&lt;br /&gt;
   # followed  by 'available' and 'creating'. If replicated share and&lt;br /&gt;
   # not undergoing a 'replication_change', only 'active' instances are&lt;br /&gt;
   # preferred.&lt;br /&gt;
   result = None&lt;br /&gt;
   if len(self.instances) &amp;gt; 0:&lt;br /&gt;
       order = [constants.STATUS_REPLICATION_CHANGE,&lt;br /&gt;
                constants.STATUS_AVAILABLE, constants.STATUS_CREATING]&lt;br /&gt;
       other_statuses = ([x['status'] for x in self.instances&lt;br /&gt;
                          if x['status'] not in order])&lt;br /&gt;
       order.extend(other_statuses)&lt;br /&gt;
       sorted_instances = sorted(&lt;br /&gt;
           self.instances, key=lambda x: order.index(x['status']))&lt;br /&gt;
       select_instances = sorted_instances&lt;br /&gt;
       if (select_instances[0]['status'] !=&lt;br /&gt;
               constants.STATUS_REPLICATION_CHANGE):&lt;br /&gt;
           select_instances = (&lt;br /&gt;
               list(filter(lambda x: x['replica_state'] ==&lt;br /&gt;
                           constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
                           sorted_instances)) or sorted_instances&lt;br /&gt;
           )&lt;br /&gt;
       result = select_instances[0]&lt;br /&gt;
   return result&lt;br /&gt;
&lt;br /&gt;
* New field on Share:&lt;br /&gt;
  replication_type = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
* New field on ShareInstance&lt;br /&gt;
  replica_state = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API Design==&lt;br /&gt;
  GET /share-replicas/&lt;br /&gt;
  GET /share-replicas?share-id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
  GET /share-replicas/&amp;lt;replica_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  POST /share-replicas/&amp;lt;share-id&amp;gt;&lt;br /&gt;
  Body:&lt;br /&gt;
  {&lt;br /&gt;
    'share_replica':&lt;br /&gt;
    {&lt;br /&gt;
      'availability_zone':&amp;lt;availability_zone_id&amp;gt;,&lt;br /&gt;
      'share_id':&amp;lt;share_id&amp;gt;,&lt;br /&gt;
      'share_network_id':&amp;lt;share_network_id&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  POST /share-replicas/&amp;lt;replica-id&amp;gt;/action&lt;br /&gt;
  Body:&lt;br /&gt;
  {'os-promote_replica': null}&lt;br /&gt;
&lt;br /&gt;
  DELETE /share-replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
&lt;br /&gt;
policy.json - All replication group policies should default to the default policy&lt;br /&gt;
    &amp;quot;share_replica:get_all&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:show&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:create&amp;quot; : &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:delete&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:promote&amp;quot;: &amp;quot;rule:default&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
Only a single replication driver method will be called at a time for a given share as they are locked by share id.&lt;br /&gt;
&lt;br /&gt;
  def create_replica(self, context, active_replica, new_replica,&lt;br /&gt;
                   access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Replicate the active replica to a new replica on this backend.&lt;br /&gt;
      :param context: Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              &amp;lt;models.ShareInstanceExportLocations&amp;gt;._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param new_replica: The share replica dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'out_of_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica being created.&lt;br /&gt;
      :return: (export_locations, replica_state)&lt;br /&gt;
      export_locations is a list of paths and replica_state is one of&lt;br /&gt;
      active, in-sync, out-of-sync or error.&lt;br /&gt;
      A backend supporting 'writable' type replication should return&lt;br /&gt;
      'active' as the replica_state.&lt;br /&gt;
      Export locations should be in the same format as returned by a&lt;br /&gt;
      share_create. This list may be empty or None.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
          .. code::&lt;br /&gt;
              [{'id': 'uuid', 'export_locations': ['export_path']}]&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def delete_replica(self, context, active_replica, replica,&lt;br /&gt;
                   share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Delete a replica.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param replica: Dictionary of the share replica being deleted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be deleted.&lt;br /&gt;
      :return: None.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def promote_replica(self, context, replica_list, replica, access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Promote a replica to 'active' replica state.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param replica_list: List of all replicas for a particular share.&lt;br /&gt;
      This list also contains the replica to be promoted. The 'active'&lt;br /&gt;
      replica will have its 'replica_state' attr set to 'active'.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          [&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'active',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              ...&lt;br /&gt;
          ]&lt;br /&gt;
      :param replica: Dictionary of the replica to be promoted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be promoted.&lt;br /&gt;
      :return: updated_replica_list or None&lt;br /&gt;
          The driver can return the updated list as in the request&lt;br /&gt;
          parameter. Changes that will be updated to the Database are:&lt;br /&gt;
          'export_locations' and 'replica_state'.&lt;br /&gt;
      :raises Exception&lt;br /&gt;
          This can be any exception derived from BaseException. This is&lt;br /&gt;
          re-raised by the manager after some necessary cleanup. If the&lt;br /&gt;
          driver raises an exception during promotion, it is assumed&lt;br /&gt;
          that all of the replicas of the share are in an inconsistent&lt;br /&gt;
          state. Recovery is only possible through the periodic update&lt;br /&gt;
          call and/or administrator intervention to correct the 'status'&lt;br /&gt;
          of the affected replicas if they become healthy again.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      def update_replica_state(self, context, replica, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Update the replica_state of a replica.&lt;br /&gt;
        Drivers should fix replication relationships that were broken if&lt;br /&gt;
        possible inside this method.&lt;br /&gt;
        :param context:Current context&lt;br /&gt;
        :param replica: Dictionary of the replica being updated.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
             .. code::&lt;br /&gt;
            {&lt;br /&gt;
            'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
            'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'deleted': False,&lt;br /&gt;
            'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
            'status': 'available',&lt;br /&gt;
            'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'terminated_at': None,&lt;br /&gt;
            'replica_state': 'active',&lt;br /&gt;
            'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
            'export_locations': [&lt;br /&gt;
                models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
            ],&lt;br /&gt;
            'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
            }&lt;br /&gt;
        :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None&lt;br /&gt;
        :return: replica_state&lt;br /&gt;
            replica_state - a str value denoting the replica_state that the&lt;br /&gt;
            replica can have. Valid values are 'in_sync' and 'out_of_sync'&lt;br /&gt;
            or None (to leave the current replica_state unchanged).&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
==Manila Client==&lt;br /&gt;
    share-replica-create Creates a replica&lt;br /&gt;
    share-replica-delete Remove one or more share replicas.&lt;br /&gt;
    share-replica-list  List share replicas.&lt;br /&gt;
    share-replica-promote Promote replica to active replica.&lt;br /&gt;
    share-replica-show  Show details about a replica.&lt;br /&gt;
&lt;br /&gt;
==First-Party Driver==&lt;br /&gt;
DR will require first-party driver support before it can be promoted from an experimental feature for two main reasons. 1. A feature is not truly open if only a single vendor can develop it due to it only being supported by a proprietary driver. 2. In order to ensure the quality of a feature, it must be testable in upstream gate.&lt;br /&gt;
&lt;br /&gt;
=FAQs=&lt;br /&gt;
# '''How do we deal with Network issues in multi-SVM replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If we choose to make replication a single-svm-only feature, the share-network API doesn't need to change. In order to support replication with share-networks, we also need to modify the share-network create API which allows creation of share networks with a table of AZ-to-subnet mappings. This approach allows us to keep a single share-network per share (with associated security service) while allowing the tenant to specify enough information that each share instance can be attached to the appropriate network in each AZ. Multi-AZ share networks would also be useful for non-replicated use cases.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we support Pool-level Replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Some vendors have suggested that certain backends can mirror groups of shares or whole pools more efficiently than individual shares. This design only addresses the mirroring of individual shares. In the future, we may allow allow replication of groups of shares, but only if those groups are contained within a single tenant and defined by the tenant.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''From where to where do we allow replication? Is it intra-cloud or inter-cloud? Do we allow replication to something that's not managed by Manila?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Intra-cloud. Replicating to something outside of Manila allows a bit more freedom, but with significantly less value, because there's practically nothing we can do to automate the failover/failback portion of a disaster. For use cases involving replication outside of Manila, we would need to involve other tools with more breadth/scope to manage the process.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Who configures the replication? The admin? The end user? The manila scheduler?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The end user. In the original design we presumed that the actual replication relationships should be hidden from the end user, but this doesn't match well with the concept of AZs that we are adding to Manila. If the users need to have control over which AZ the primary copy of their data lives in, then they also need to control where the other copies live. This means that the administrator's job is to ensure that for any share type that is replicated, it can be replicated from any AZ to any other AZ.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Is replication supported only intra-region or inter-region as well? How about intra-AZ vs inter-AZ?''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This design is for intra-region only. Inter-region replication is clearly a feature we want, but it would look pretty different from intra-region replication; this design does not cover that. Intra-AZ replication is supported, however inter-AZ replication is recommended as AZs should be perceived as failure domains.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Unanswered Questions=&lt;br /&gt;
# '''Is there no way to achieve non-disruptive failover?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(bswartz) I would love to find out that our initial intuition here is wrong, because it would change a lot of aspects of the design. It's worth spending time to brainstorm and research possibilities in this area. So far the most promising ideas involve:&lt;br /&gt;
#*Using VirtFS to mediate filesystem access and achieving non-disruptive failover that way&lt;br /&gt;
#*Using some kind of agent inside the guests to mediate file access&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Can a replica have a different share_type? There is a valid use case where a user would want to create a share replica on backend with different capabilities than the one the original share resides on. For instance, replicas might need to be on a less expensive backend. In that case, can the replica have a different share_type altogether?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;quot;Currently&amp;quot;, we inherit the share_type of the share and believe that replication has to be on symmetric terms, where both backends have similar capabilities.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''Can we allow the driver to restrict replication support between available backends? Backends may support replication to other compatible backends only. Hence, they must report some sort of information to the scheduler so that when creating a replica for an existing share, the scheduler would use that information to schedule the creation of the replica. What information should this be?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) We're investigating including 'driver_class_name' in a ReplicationFilter, including the possibility of backend reported configuration, 'replication_partners'.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How are access rules persisted across replicas/share instances?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#*Do all replicas have the same access rules applied? (gouthamr): This is Currently being pursued&lt;br /&gt;
#*Should access rules be applied only to &amp;quot;active&amp;quot; replicas?&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How does migration affect replicated shares?'''&lt;br /&gt;
#*(gouthamr)In the Tokyo summit, it was decided that we currently disallow migration of a share that has replicas. The replication relationships must be broken and reestablished after the migration is complete in order to migrate a share with replicas.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we need an API to initiate a sync? (resync or force-update)''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This is a great idea and one certain use case is during planned failovers. (gouthamr)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''How to recover from promotion failures?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) Currently, if some exception occurs at the driver level, the replicas are rendered useless. Should we provide escape hatches to avoid complete loss in case these are recoverable exceptions? The administrator has the ability to 'reset-state' and affect the 'status' of any replica. Currently, there exists no API to 'reset-replica-state' for a replica.&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
These examples assume that the replicas exist in different AZs.&lt;br /&gt;
&lt;br /&gt;
== Writable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=writeable&lt;br /&gt;
# Administrator creates a new share_type called foo&lt;br /&gt;
# Administrator sets replication_type=writeable extra spec on share type foo&lt;br /&gt;
# User creates new share of type foo in AZ b1&lt;br /&gt;
# Share is created with replication_type=writeable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to active (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 writes some data to the share, which is immediately visible to client1&lt;br /&gt;
&lt;br /&gt;
== Readable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=readable&lt;br /&gt;
# Administrator creates a new share_type called bar&lt;br /&gt;
# Administrator sets replication_type=readable extra spec on share type bar&lt;br /&gt;
# User creates new share of type bar in AZ b1&lt;br /&gt;
# Share is created with replication_type=readable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to in_sync (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 cannot write data to the share but continues to see updates&lt;br /&gt;
&lt;br /&gt;
== Failover/failback example ==&lt;br /&gt;
&lt;br /&gt;
(Continued from above)&lt;br /&gt;
# An outage occurs in AZ b1&lt;br /&gt;
# Administrator sends out a bulletin about the outage to his users &amp;quot;the power transformer in b1 turned to slag, it will be 12 hours before it can be replaced, please bear with us, yada yada&amp;quot;&lt;br /&gt;
# User notices that his application on client1 is no longer running, and investigates&lt;br /&gt;
# User finds out that client1 is gone, and reads a bulletin from the admin explaining why&lt;br /&gt;
# User notes that the b1 replica is his share is still active and the b2 replica is in_sync, while the state of the share is available&lt;br /&gt;
# User calls set active replica to AZ b2 on his share&lt;br /&gt;
# The share goes to state replication_change and access to the share is briefly lost on client2&lt;br /&gt;
# The state of replica b2 changes to active and the state of replica b1 changes to out_of_sync after Manila fails to contact the original primary. The state of the share changes back to available, and access is restored on client2&lt;br /&gt;
# User starts his application on client2, and the application recovers from an apparent crash, with a consistent copy of the application's data&lt;br /&gt;
# User application is back up and running, disaster is averted&lt;br /&gt;
# Eventually maintenance on the b1 AZ is completed, and all of the equipment is reactivated&lt;br /&gt;
# Administrator sends out a bulletin to his users about the outage ending &amp;quot;we replaced the transformer with a better one, everything is back online, thanks for your understanding, yada yada&amp;quot;&lt;br /&gt;
# Manila notices the out_of_sync replica is reachable and initiates a resync, bringing the b1 replica in_sync within a short time&lt;br /&gt;
# After some time, the users reads the bulletin and observes that his share is being replicated again. He decides to intentionally move back to b1.&lt;br /&gt;
# User gracefully shuts down his application, and flushes I/O&lt;br /&gt;
# User calls set active replica to AZ b1 on his share&lt;br /&gt;
# The share goes to state replication_change and no disruption is observed because the application is shut down&lt;br /&gt;
# The state of replica b1 changes to active and the state of replica b2 changes to in_sync after Manila reverses the replication again. The state of the share changes back to available&lt;br /&gt;
# User starts his application on client1, and the application starts cleanly, having been shut down gracefully&lt;br /&gt;
&lt;br /&gt;
=Implementation Progress=&lt;br /&gt;
===Core Work===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manila-share-replication Blueprint for Core API/Scheduler implementation]&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manilaclient-share-replication Blueprint for Client implementation]&lt;br /&gt;
&lt;br /&gt;
===Ex Driver Implementation===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/netapp-cdot-single-svm-replication Blueprint for cDOT Driver Implementation]&lt;br /&gt;
&lt;br /&gt;
=Older Design Pages=&lt;br /&gt;
* Replication Use Cases: https://wiki.openstack.org/wiki/Manila/Replication_Use_Cases&lt;br /&gt;
* Design Notes: https://wiki.openstack.org/wiki/Manila/Replication_Design_Notes&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=98830</id>
		<title>Manila/design/manila-mitaka-data-replication</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=98830"/>
				<updated>2015-12-04T15:51:12Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Driver API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=Manila Disaster Recovery / Data Replication Design=&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Replicated shares will be implemented in Manila without adding any new services or any new drivers. The code for creating replicated shares and for adding/removing replicas and other replication-related operations will all go into the existing share drivers. The most significant change required to allow this will be that share drivers will be responsible for communicating with ALL storage controllers necessary to achieve any replication tasks, even if that involves sending commands to other storage controllers in other AZs.&lt;br /&gt;
&lt;br /&gt;
While we can't know how every storage controller works and how each vendor will implement replication, this approach should give driver writers all the flexibility needed to implement what they need with minimal added complexity in the Manila core. There are already examples of drivers reading config sections for other drivers when a operation requires communicating with 2 backends. The Manila Share Manager itself is expected to communicate all necessary backend details for share replicas that exist across AZs to a backend which it requests an operation upon.&lt;br /&gt;
&lt;br /&gt;
Intra-AZ replication is supported, but in an ideal solution, AZs should be perceived as failure domains. So this feature tends to shine in an inter-AZ replication use case. &lt;br /&gt;
&lt;br /&gt;
===Supported Replication Types===&lt;br /&gt;
There are 3 styles of DR that we would like to support in the long run:&lt;br /&gt;
&lt;br /&gt;
# writable - Amazon EFS-style synchronously replicated shares where all replicas are writable. Promotion it not supported and not needed.&lt;br /&gt;
# readable - Mirror-style replication with a primary (writable) copy and one or more secondary (read-only) copies which can become writable after a promotion of the secondary.&lt;br /&gt;
# dr - Generalized replication with secondary copies that are inaccessible until after a promotion of one of the secondary copies.&lt;br /&gt;
&lt;br /&gt;
===Replica States===&lt;br /&gt;
Each replica has a ''replica_state'' which has 4 possible values:&lt;br /&gt;
&lt;br /&gt;
# active - All writable replicas are active.&lt;br /&gt;
# in_sync - Passive replica which is up to date with the active replica, and can be promoted to active.&lt;br /&gt;
# out_of_sync - Passive replica which has gone out of date, or new replica that is not yet up to date.&lt;br /&gt;
# error - Either the scheduler failed to schedule this replica or some irrecoverable damage occurred during promotion of a non-active replica. Drivers may set the ''replica_state'' to ''error'' if some irrecoverable damage to the replica is discovered at any point during its existence. (through the periodic ''replica_state'' update)&lt;br /&gt;
[[File:Manila instance replication states.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New share state===&lt;br /&gt;
replication_change - New transient state triggered by a change of the active replica. Access to the share is cut off while in this state.&lt;br /&gt;
&lt;br /&gt;
===Promotion===&lt;br /&gt;
For '''readable''' and '''dr''' styles, we refer to the task of switching a non-active replica with the '''active''' replica as '''promotion'''. For the '''writable''' style of replication, '''promotion''' does not make sense since all replicas are '''active''' (writable) at all given points of time. Promotion of replicas with '''replica_state''' set to '''out_of_sync''' or '''error''' may be unsupported by the backend. However, we would like to allow the action as an administrator feature and such an attempt may be honored by backends if possible. &lt;br /&gt;
&lt;br /&gt;
When multiple replicas exist, multiple replication relationships between shares may need to be redefined at the backend. If the driver fails at this stage, the replicas may be left at an inconsistent state. The manager will set all replica instances to have '''replica_state''' and '''status''' to '''error'''. Recovery from this stage would require administrator intervention.&lt;br /&gt;
&lt;br /&gt;
==User Workflows==&lt;br /&gt;
====Creating a share supporting replication====&lt;br /&gt;
* Administrators can create a share type with extra-spec ''replication_type'', specifying the style of replication the backend supports.&lt;br /&gt;
* Users can use the share type to create a new share that allows/supports replication.&lt;br /&gt;
* A replicated share always starts out with one replica instance, the share itself. This should not be confused as the share having a replica already. The user can verify if the share has any replicas by requesting the details of the share.&lt;br /&gt;
&lt;br /&gt;
====Creating a replica====&lt;br /&gt;
* POST to /share-replicas&lt;br /&gt;
User has to specify the share name/id of the share that is supposed to be replicated, an availability zone for the replica to exist in and optionally a share_network_id.&lt;br /&gt;
According to existing design, replicas of a share cannot exist in the same availability zone as the share itself.&lt;br /&gt;
* A newly created share_replica starts out in ''out_of_sync'' state and might transition to ''in_sync'' state when the driver reports this state.&lt;br /&gt;
&lt;br /&gt;
====Listing and showing replicas====&lt;br /&gt;
* GET from /share-replicas&lt;br /&gt;
User can list all replicas and verify their ''status'' and ''replica_state''.&lt;br /&gt;
* GET from /share-replicas?share_id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
User can list replicas for a particular share.&lt;br /&gt;
* GET from /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
User can view details of a replica.&lt;br /&gt;
&lt;br /&gt;
====Promoting a non-active replica====&lt;br /&gt;
* POST to /share-replicas/action with body {'promote': None}&lt;br /&gt;
For replication types that permit promotion, the user can promote a replica with ''in_sync'' replica_state to ''active'' replica_state by initiating the ''promote_replica'' call.&lt;br /&gt;
* Only administrators can attempt promoting replicas with replica_state ''error'' or ''out_of_sync''.&lt;br /&gt;
&lt;br /&gt;
====Deleting Replicas====&lt;br /&gt;
* DELETE to /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
The user can delete a replica. The last ''active'' replica cannot be deleted using this ''delete_replica'' call.&lt;br /&gt;
&lt;br /&gt;
==System Workflows==&lt;br /&gt;
* Creating a share that supports replication&lt;br /&gt;
** Same process as creating a new share.&lt;br /&gt;
** The ''replication_type'' extra-spec from the share-type is copied over to the share''s data on the DB.&lt;br /&gt;
** Scheduler uses the ''replication_type'' extra-spec to filter available hosts and schedule the share on an appropriate backend that supports that specific style of ''replication_type''.&lt;br /&gt;
&lt;br /&gt;
* Creating a replica:&lt;br /&gt;
** Create a share instance on the database.&lt;br /&gt;
** Update the share instance ''replica_state'' to ''out_of_sync''.&lt;br /&gt;
** Cast a call to the scheduler to find an appropriate host to schedule the replica on.&lt;br /&gt;
** In the scheduler, find weighted host for the replica.&lt;br /&gt;
*** If host cannot be chosen, update the replica's ''status'' and ''replica_state'' on the Database to ''error''. Throw an exception.&lt;br /&gt;
** Cast the create_share_replica call to the driver based on the weighted host selection.&lt;br /&gt;
** Prior to invoking the driver's call, collate information regarding existing ''active'' replica instance, existing share access rules and the replica's share_server, pass these to the driver while invoking ''create_replica''.&lt;br /&gt;
** The driver may return ''export_locations'' and ''replica_state''. If they are returned, the database is updated with these values.&lt;br /&gt;
** If the ''replication_type'' is ''writable'', the driver MUST return the ''replica_state'' set to ''active''.&lt;br /&gt;
** All the access rules for the new replica are set to ''active'' state on the database.&lt;br /&gt;
** The driver may throw an exception, update the ''status'' and ''replica_state'' of the replica to ''error''.&lt;br /&gt;
&lt;br /&gt;
* Listing/showing shares:&lt;br /&gt;
** For shares that support replication, the result of listing/showing the share will have new fields, ''replication_type'': denoting the replication style supported and ''has_replicas'' to denote if the share has replicas.&lt;br /&gt;
** For replicated shares, the primary instance for the share must be preferred among those replicas that have a status ''replication_change'' or among those that have a replica_state set to ''active''.&lt;br /&gt;
&lt;br /&gt;
* Listing replicas&lt;br /&gt;
** For listing, Grab share instances from the database that have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** If share_id is provided, grab only share instances that belong to that share and have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** Limits and offsets must be respected on the list calls.&lt;br /&gt;
&lt;br /&gt;
* Promoting a non-active replica:&lt;br /&gt;
** If replica is already active, do nothing.&lt;br /&gt;
** Update the ''status'' of the replica being promoted to ''replication_change''.&lt;br /&gt;
** Grab all available replicas and invoke the appropriate driver''s promote_replica call by passing the available replicas and the new replica.&lt;br /&gt;
** If the driver throws an exception at this stage, there is a good chance that the replicas are somehow altered on the backend. Loop through the replicas and set their ''replica_state''s to ''error'' and leave the ''status'' unchanged. Also set the ''status'' of the replica that failed to promote to ''available'' as before this operation. The backend may choose to update the actual replica_state during the replica monitoring call.&lt;br /&gt;
** The driver may return an updated list of replicas. Update the ''export_locations'' and ''replica_state''s to the database.&lt;br /&gt;
** The ''status'' of the replica that was promoted should return to ''available'' from ''replication_change''.&lt;br /&gt;
&lt;br /&gt;
* Periodic replica update:&lt;br /&gt;
** The share manager implements a looping call with default interval of 5 minutes to query from each driver and each backend the ''replica_state'' of all non-active replicas that are associated with them.&lt;br /&gt;
** The driver is allowed to set the ''replica_state'' to ''in_sync'', ''out_of_sync'', and in exceptional cases, ''error''.&lt;br /&gt;
** If the driver sets the ''replica_state'' of a replica to ''error'', it is assumed that some irrecoverable damage has occured to the replica instance. The ''status'' of the replica instance must be set to ''error'' as well.&lt;br /&gt;
&lt;br /&gt;
* Deleting a share replica&lt;br /&gt;
** If the replica had no host, it is simply removed from the database.&lt;br /&gt;
** The ''status'' of the replica is set to ''deleting'' on the database and the appropriate driver method is called to delete the replica.&lt;br /&gt;
** If the driver fails to delete the replica, the ''status'' of the replica is updated to ''error_deleting'' on the database.&lt;br /&gt;
** If the driver returns without errors, the replica instance is removed from the database.&lt;br /&gt;
&lt;br /&gt;
==Scheduler Impact==&lt;br /&gt;
* The host_manager must update the ''replication_type'' capability from the backend. The backends must report this capability at the host/pool level.&lt;br /&gt;
* The filter_scheduler must then match the ''replication_type'' capability with the capability that the replication share_type demands.&lt;br /&gt;
* The ''replication_type'' must be one of the styles mentioned [[#Supported Replication Styles|above]].&lt;br /&gt;
&lt;br /&gt;
==DB Impact==&lt;br /&gt;
* Share Export Locations:&lt;br /&gt;
Preferred export locations will only be from the instances with ''replica_state'' set to ''active''.&lt;br /&gt;
  def export_locations(self):&lt;br /&gt;
      # TODO(gouthamr): Return AZ specific export locations for replicated&lt;br /&gt;
      #  shares&lt;br /&gt;
      # NOTE(gouthamr): For a replicated share, export locations of the&lt;br /&gt;
      # 'active' instances are taken, if 'available'.&lt;br /&gt;
      all_export_locations = []&lt;br /&gt;
      select_instances = list(filter(&lt;br /&gt;
          lambda x: x['replica_state'] == constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
          self.instances)) or self.instances&lt;br /&gt;
      for instance in select_instances:&lt;br /&gt;
          if instance['status'] == constants.STATUS_AVAILABLE:&lt;br /&gt;
              for export_location in instance.export_locations:&lt;br /&gt;
                  all_export_locations.append(export_location['path'])&lt;br /&gt;
    return all_export_locations&lt;br /&gt;
&lt;br /&gt;
* Share Instance:&lt;br /&gt;
Preferred instance will be an instance with ''status'' set to ''replication_change'' or any instance with ''status'' set to ''available'' and ''replica_state'' set to ''active''.&lt;br /&gt;
  def instance(self):&lt;br /&gt;
   # NOTE(gouthamr): The order of preference: status 'replication_change',&lt;br /&gt;
   # followed  by 'available' and 'creating'. If replicated share and&lt;br /&gt;
   # not undergoing a 'replication_change', only 'active' instances are&lt;br /&gt;
   # preferred.&lt;br /&gt;
   result = None&lt;br /&gt;
   if len(self.instances) &amp;gt; 0:&lt;br /&gt;
       order = [constants.STATUS_REPLICATION_CHANGE,&lt;br /&gt;
                constants.STATUS_AVAILABLE, constants.STATUS_CREATING]&lt;br /&gt;
       other_statuses = ([x['status'] for x in self.instances&lt;br /&gt;
                          if x['status'] not in order])&lt;br /&gt;
       order.extend(other_statuses)&lt;br /&gt;
       sorted_instances = sorted(&lt;br /&gt;
           self.instances, key=lambda x: order.index(x['status']))&lt;br /&gt;
       select_instances = sorted_instances&lt;br /&gt;
       if (select_instances[0]['status'] !=&lt;br /&gt;
               constants.STATUS_REPLICATION_CHANGE):&lt;br /&gt;
           select_instances = (&lt;br /&gt;
               list(filter(lambda x: x['replica_state'] ==&lt;br /&gt;
                           constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
                           sorted_instances)) or sorted_instances&lt;br /&gt;
           )&lt;br /&gt;
       result = select_instances[0]&lt;br /&gt;
   return result&lt;br /&gt;
&lt;br /&gt;
* New field on Share:&lt;br /&gt;
  replication_type = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
* New field on ShareInstance&lt;br /&gt;
  replica_state = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API Design==&lt;br /&gt;
  GET /share-replicas/&lt;br /&gt;
  GET /share-replicas?share-id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
  GET /share-replicas/&amp;lt;replica_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  POST /share-replicas/&amp;lt;share-id&amp;gt;&lt;br /&gt;
  Body:&lt;br /&gt;
  {&lt;br /&gt;
    'share_replica':&lt;br /&gt;
    {&lt;br /&gt;
      'availability_zone':&amp;lt;availability_zone_id&amp;gt;,&lt;br /&gt;
      'share_id':&amp;lt;share_id&amp;gt;,&lt;br /&gt;
      'share_network_id':&amp;lt;share_network_id&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  POST /share-replicas/&amp;lt;replica-id&amp;gt;/action&lt;br /&gt;
  Body:&lt;br /&gt;
  {'os-promote_replica': null}&lt;br /&gt;
&lt;br /&gt;
  DELETE /share-replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
&lt;br /&gt;
policy.json - All replication group policies should default to the default policy&lt;br /&gt;
    &amp;quot;share_replica:get_all&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:show&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:create&amp;quot; : &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:delete&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:promote&amp;quot;: &amp;quot;rule:default&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
Only a single replication driver method will be called at a time for a given share as they are locked by share id.&lt;br /&gt;
&lt;br /&gt;
  def create_replica(self, context, active_replica, new_replica,&lt;br /&gt;
                   access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Replicate the active replica to a new replica on this backend.&lt;br /&gt;
      :param context: Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              &amp;lt;models.ShareInstanceExportLocations&amp;gt;._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param new_replica: The share replica dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'out_of_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica being created.&lt;br /&gt;
      :return: (export_locations, replica_state)&lt;br /&gt;
      export_locations is a list of paths and replica_state is one of&lt;br /&gt;
      active, in-sync, out-of-sync or error.&lt;br /&gt;
      A backend supporting 'writable' type replication should return&lt;br /&gt;
      'active' as the replica_state.&lt;br /&gt;
      Export locations should be in the same format as returned by a&lt;br /&gt;
      share_create. This list may be empty or None.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
          .. code::&lt;br /&gt;
              [{'id': 'uuid', 'export_locations': ['export_path']}]&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def delete_replica(self, context, active_replica, replica,&lt;br /&gt;
                   share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Delete a replica.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param replica: Dictionary of the share replica being deleted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be deleted.&lt;br /&gt;
      :return: None.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def promote_replica(self, context, replica_list, replica, access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Promote a replica to 'active' replica state.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param replica_list: List of all replicas for a particular share.&lt;br /&gt;
      This list also contains the replica to be promoted. The 'active'&lt;br /&gt;
      replica will have its 'replica_state' attr set to 'active'.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          [&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'active',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              ...&lt;br /&gt;
          ]&lt;br /&gt;
      :param replica: Dictionary of the replica to be promoted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be promoted.&lt;br /&gt;
      :return: updated_replica_list or None&lt;br /&gt;
          The driver can return the updated list as in the request&lt;br /&gt;
          parameter. Changes that will be updated to the Database are:&lt;br /&gt;
          'export_locations' and 'replica_state'.&lt;br /&gt;
      :raises Exception&lt;br /&gt;
          This can be any exception derived from BaseException. This is&lt;br /&gt;
          re-raised by the manager after some necessary cleanup. If the&lt;br /&gt;
          driver raises an exception during promotion, it is assumed&lt;br /&gt;
          that all of the replicas of the share are in an inconsistent&lt;br /&gt;
          state. Recovery is only possible through the periodic update&lt;br /&gt;
          call and/or administrator intervention to correct the 'status'&lt;br /&gt;
          of the affected replicas if they become healthy again.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      def update_replica_state(self, context, replica, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Update the replica_state of a replica.&lt;br /&gt;
        Drivers should fix replication relationships that were broken if&lt;br /&gt;
        possible inside this method.&lt;br /&gt;
        :param context:Current context&lt;br /&gt;
        :param replica: Dictionary of the replica being updated.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
             .. code::&lt;br /&gt;
            {&lt;br /&gt;
            'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
            'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'deleted': False,&lt;br /&gt;
            'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
            'status': 'available',&lt;br /&gt;
            'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'terminated_at': None,&lt;br /&gt;
            'replica_state': 'active',&lt;br /&gt;
            'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
            'export_locations': [&lt;br /&gt;
                models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
            ],&lt;br /&gt;
            'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
            }&lt;br /&gt;
        :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None&lt;br /&gt;
        :return: replica_state&lt;br /&gt;
            replica_state - a str value denoting the replica_state that the&lt;br /&gt;
            replica can have. Valid values are 'in_sync' and 'out_of_sync'&lt;br /&gt;
            or None (to leave the current replica_state unchanged).&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
==Manila Client==&lt;br /&gt;
    share-replica-create Creates a replica&lt;br /&gt;
    share-replica-delete Remove one or more share replicas.&lt;br /&gt;
    share-replica-list  List share replicas.&lt;br /&gt;
    share-replica-promote Promote replica to active replica.&lt;br /&gt;
    share-replica-show  Show details about a replica.&lt;br /&gt;
&lt;br /&gt;
=FAQs=&lt;br /&gt;
# '''How do we deal with Network issues in multi-SVM replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If we choose to make replication a single-svm-only feature, the share-network API doesn't need to change. In order to support replication with share-networks, we also need to modify the share-network create API which allows creation of share networks with a table of AZ-to-subnet mappings. This approach allows us to keep a single share-network per share (with associated security service) while allowing the tenant to specify enough information that each share instance can be attached to the appropriate network in each AZ. Multi-AZ share networks would also be useful for non-replicated use cases.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we support Pool-level Replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Some vendors have suggested that certain backends can mirror groups of shares or whole pools more efficiently than individual shares. This design only addresses the mirroring of individual shares. In the future, we may allow allow replication of groups of shares, but only if those groups are contained within a single tenant and defined by the tenant.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''From where to where do we allow replication? Is it intra-cloud or inter-cloud? Do we allow replication to something that's not managed by Manila?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Intra-cloud. Replicating to something outside of Manila allows a bit more freedom, but with significantly less value, because there's practically nothing we can do to automate the failover/failback portion of a disaster. For use cases involving replication outside of Manila, we would need to involve other tools with more breadth/scope to manage the process.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Who configures the replication? The admin? The end user? The manila scheduler?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The end user. In the original design we presumed that the actual replication relationships should be hidden from the end user, but this doesn't match well with the concept of AZs that we are adding to Manila. If the users need to have control over which AZ the primary copy of their data lives in, then they also need to control where the other copies live. This means that the administrator's job is to ensure that for any share type that is replicated, it can be replicated from any AZ to any other AZ.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Is replication supported only intra-region or inter-region as well? How about intra-AZ vs inter-AZ?''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This design is for intra-region only. Inter-region replication is clearly a feature we want, but it would look pretty different from intra-region replication; this design does not cover that. Intra-AZ replication is supported, however inter-AZ replication is recommended as AZs should be perceived as failure domains.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Unanswered Questions=&lt;br /&gt;
# '''Is there no way to achieve non-disruptive failover?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(bswartz) I would love to find out that our initial intuition here is wrong, because it would change a lot of aspects of the design. It's worth spending time to brainstorm and research possibilities in this area. So far the most promising ideas involve:&lt;br /&gt;
#*Using VirtFS to mediate filesystem access and achieving non-disruptive failover that way&lt;br /&gt;
#*Using some kind of agent inside the guests to mediate file access&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Can a replica have a different share_type? There is a valid use case where a user would want to create a share replica on backend with different capabilities than the one the original share resides on. For instance, replicas might need to be on a less expensive backend. In that case, can the replica have a different share_type altogether?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;quot;Currently&amp;quot;, we inherit the share_type of the share and believe that replication has to be on symmetric terms, where both backends have similar capabilities.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''Can we allow the driver to restrict replication support between available backends? Backends may support replication to other compatible backends only. Hence, they must report some sort of information to the scheduler so that when creating a replica for an existing share, the scheduler would use that information to schedule the creation of the replica. What information should this be?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) We're investigating including 'driver_class_name' in a ReplicationFilter, including the possibility of backend reported configuration, 'replication_partners'.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How are access rules persisted across replicas/share instances?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#*Do all replicas have the same access rules applied? (gouthamr): This is Currently being pursued&lt;br /&gt;
#*Should access rules be applied only to &amp;quot;active&amp;quot; replicas?&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How does migration affect replicated shares?'''&lt;br /&gt;
#*(gouthamr)In the Tokyo summit, it was decided that we currently disallow migration of a share that has replicas. The replication relationships must be broken and reestablished after the migration is complete in order to migrate a share with replicas.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we need an API to initiate a sync? (resync or force-update)''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This is a great idea and one certain use case is during planned failovers. (gouthamr)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''How to recover from promotion failures?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) Currently, if some exception occurs at the driver level, the replicas are rendered useless. Should we provide escape hatches to avoid complete loss in case these are recoverable exceptions? The administrator has the ability to 'reset-state' and affect the 'status' of any replica. Currently, there exists no API to 'reset-replica-state' for a replica.&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
These examples assume that the replicas exist in different AZs.&lt;br /&gt;
&lt;br /&gt;
== Writable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=writeable&lt;br /&gt;
# Administrator creates a new share_type called foo&lt;br /&gt;
# Administrator sets replication_type=writeable extra spec on share type foo&lt;br /&gt;
# User creates new share of type foo in AZ b1&lt;br /&gt;
# Share is created with replication_type=writeable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to active (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 writes some data to the share, which is immediately visible to client1&lt;br /&gt;
&lt;br /&gt;
== Readable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=readable&lt;br /&gt;
# Administrator creates a new share_type called bar&lt;br /&gt;
# Administrator sets replication_type=readable extra spec on share type bar&lt;br /&gt;
# User creates new share of type bar in AZ b1&lt;br /&gt;
# Share is created with replication_type=readable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to in_sync (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 cannot write data to the share but continues to see updates&lt;br /&gt;
&lt;br /&gt;
== Failover/failback example ==&lt;br /&gt;
&lt;br /&gt;
(Continued from above)&lt;br /&gt;
# An outage occurs in AZ b1&lt;br /&gt;
# Administrator sends out a bulletin about the outage to his users &amp;quot;the power transformer in b1 turned to slag, it will be 12 hours before it can be replaced, please bear with us, yada yada&amp;quot;&lt;br /&gt;
# User notices that his application on client1 is no longer running, and investigates&lt;br /&gt;
# User finds out that client1 is gone, and reads a bulletin from the admin explaining why&lt;br /&gt;
# User notes that the b1 replica is his share is still active and the b2 replica is in_sync, while the state of the share is available&lt;br /&gt;
# User calls set active replica to AZ b2 on his share&lt;br /&gt;
# The share goes to state replication_change and access to the share is briefly lost on client2&lt;br /&gt;
# The state of replica b2 changes to active and the state of replica b1 changes to out_of_sync after Manila fails to contact the original primary. The state of the share changes back to available, and access is restored on client2&lt;br /&gt;
# User starts his application on client2, and the application recovers from an apparent crash, with a consistent copy of the application's data&lt;br /&gt;
# User application is back up and running, disaster is averted&lt;br /&gt;
# Eventually maintenance on the b1 AZ is completed, and all of the equipment is reactivated&lt;br /&gt;
# Administrator sends out a bulletin to his users about the outage ending &amp;quot;we replaced the transformer with a better one, everything is back online, thanks for your understanding, yada yada&amp;quot;&lt;br /&gt;
# Manila notices the out_of_sync replica is reachable and initiates a resync, bringing the b1 replica in_sync within a short time&lt;br /&gt;
# After some time, the users reads the bulletin and observes that his share is being replicated again. He decides to intentionally move back to b1.&lt;br /&gt;
# User gracefully shuts down his application, and flushes I/O&lt;br /&gt;
# User calls set active replica to AZ b1 on his share&lt;br /&gt;
# The share goes to state replication_change and no disruption is observed because the application is shut down&lt;br /&gt;
# The state of replica b1 changes to active and the state of replica b2 changes to in_sync after Manila reverses the replication again. The state of the share changes back to available&lt;br /&gt;
# User starts his application on client1, and the application starts cleanly, having been shut down gracefully&lt;br /&gt;
&lt;br /&gt;
=Implementation Progress=&lt;br /&gt;
===Core Work===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manila-share-replication Blueprint for Core API/Scheduler implementation]&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manilaclient-share-replication Blueprint for Client implementation]&lt;br /&gt;
&lt;br /&gt;
===Ex Driver Implementation===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/netapp-cdot-single-svm-replication Blueprint for cDOT Driver Implementation]&lt;br /&gt;
&lt;br /&gt;
=Older Design Pages=&lt;br /&gt;
* Replication Use Cases: https://wiki.openstack.org/wiki/Manila/Replication_Use_Cases&lt;br /&gt;
* Design Notes: https://wiki.openstack.org/wiki/Manila/Replication_Design_Notes&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=98654</id>
		<title>Manila/design/manila-mitaka-data-replication</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-mitaka-data-replication&amp;diff=98654"/>
				<updated>2015-12-02T21:18:35Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Listing and showing replicas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
=Manila Disaster Recovery / Data Replication Design=&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
Replicated shares will be implemented in Manila without adding any new services or any new drivers. The code for creating replicated shares and for adding/removing replicas and other replication-related operations will all go into the existing share drivers. The most significant change required to allow this will be that share drivers will be responsible for communicating with ALL storage controllers necessary to achieve any replication tasks, even if that involves sending commands to other storage controllers in other AZs.&lt;br /&gt;
&lt;br /&gt;
While we can't know how every storage controller works and how each vendor will implement replication, this approach should give driver writers all the flexibility needed to implement what they need with minimal added complexity in the Manila core. There are already examples of drivers reading config sections for other drivers when a operation requires communicating with 2 backends. The Manila Share Manager itself is expected to communicate all necessary backend details for share replicas that exist across AZs to a backend which it requests an operation upon.&lt;br /&gt;
&lt;br /&gt;
Intra-AZ replication is supported, but in an ideal solution, AZs should be perceived as failure domains. So this feature tends to shine in an inter-AZ replication use case. &lt;br /&gt;
&lt;br /&gt;
===Supported Replication Types===&lt;br /&gt;
There are 3 styles of DR that we would like to support in the long run:&lt;br /&gt;
&lt;br /&gt;
# writable - Amazon EFS-style synchronously replicated shares where all replicas are writable. Promotion it not supported and not needed.&lt;br /&gt;
# readable - Mirror-style replication with a primary (writable) copy and one or more secondary (read-only) copies which can become writable after a promotion of the secondary.&lt;br /&gt;
# dr - Generalized replication with secondary copies that are inaccessible until after a promotion of one of the secondary copies.&lt;br /&gt;
&lt;br /&gt;
===Replica States===&lt;br /&gt;
Each replica has a ''replica_state'' which has 4 possible values:&lt;br /&gt;
&lt;br /&gt;
# active - All writable replicas are active.&lt;br /&gt;
# in_sync - Passive replica which is up to date with the active replica, and can be promoted to active.&lt;br /&gt;
# out_of_sync - Passive replica which has gone out of date, or new replica that is not yet up to date.&lt;br /&gt;
# error - Either the scheduler failed to schedule this replica or some irrecoverable damage occurred during promotion of a non-active replica. Drivers may set the ''replica_state'' to ''error'' if some irrecoverable damage to the replica is discovered at any point during its existence. (through the periodic ''replica_state'' update)&lt;br /&gt;
[[File:Manila instance replication states.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New share state===&lt;br /&gt;
replication_change - New transient state triggered by a change of the active replica. Access to the share is cut off while in this state.&lt;br /&gt;
&lt;br /&gt;
===Promotion===&lt;br /&gt;
For '''readable''' and '''dr''' styles, we refer to the task of switching a non-active replica with the '''active''' replica as '''promotion'''. For the '''writable''' style of replication, '''promotion''' does not make sense since all replicas are '''active''' (writable) at all given points of time. Promotion of replicas with '''replica_state''' set to '''out_of_sync''' or '''error''' may be unsupported by the backend. However, we would like to allow the action as an administrator feature and such an attempt may be honored by backends if possible. &lt;br /&gt;
&lt;br /&gt;
When multiple replicas exist, multiple replication relationships between shares may need to be redefined at the backend. If the driver fails at this stage, the replicas may be left at an inconsistent state. The manager will set all replica instances to have '''replica_state''' and '''status''' to '''error'''. Recovery from this stage would require administrator intervention.&lt;br /&gt;
&lt;br /&gt;
==User Workflows==&lt;br /&gt;
====Creating a share supporting replication====&lt;br /&gt;
* Administrators can create a share type with extra-spec ''replication_type'', specifying the style of replication the backend supports.&lt;br /&gt;
* Users can use the share type to create a new share that allows/supports replication.&lt;br /&gt;
* A replicated share always starts out with one replica instance, the share itself. This should not be confused as the share having a replica already. The user can verify if the share has any replicas by requesting the details of the share.&lt;br /&gt;
&lt;br /&gt;
====Creating a replica====&lt;br /&gt;
* POST to /share-replicas&lt;br /&gt;
User has to specify the share name/id of the share that is supposed to be replicated, an availability zone for the replica to exist in and optionally a share_network_id.&lt;br /&gt;
According to existing design, replicas of a share cannot exist in the same availability zone as the share itself.&lt;br /&gt;
* A newly created share_replica starts out in ''out_of_sync'' state and might transition to ''in_sync'' state when the driver reports this state.&lt;br /&gt;
&lt;br /&gt;
====Listing and showing replicas====&lt;br /&gt;
* GET from /share-replicas&lt;br /&gt;
User can list all replicas and verify their ''status'' and ''replica_state''.&lt;br /&gt;
* GET from /share-replicas?share_id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
User can list replicas for a particular share.&lt;br /&gt;
* GET from /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
User can view details of a replica.&lt;br /&gt;
&lt;br /&gt;
====Promoting a non-active replica====&lt;br /&gt;
* POST to /share-replicas/action with body {'promote': None}&lt;br /&gt;
For replication types that permit promotion, the user can promote a replica with ''in_sync'' replica_state to ''active'' replica_state by initiating the ''promote_replica'' call.&lt;br /&gt;
* Only administrators can attempt promoting replicas with replica_state ''error'' or ''out_of_sync''.&lt;br /&gt;
&lt;br /&gt;
====Deleting Replicas====&lt;br /&gt;
* DELETE to /share-replicas/&amp;lt;id&amp;gt;&lt;br /&gt;
The user can delete a replica. The last ''active'' replica cannot be deleted using this ''delete_replica'' call.&lt;br /&gt;
&lt;br /&gt;
==System Workflows==&lt;br /&gt;
* Creating a share that supports replication&lt;br /&gt;
** Same process as creating a new share.&lt;br /&gt;
** The ''replication_type'' extra-spec from the share-type is copied over to the share''s data on the DB.&lt;br /&gt;
** Scheduler uses the ''replication_type'' extra-spec to filter available hosts and schedule the share on an appropriate backend that supports that specific style of ''replication_type''.&lt;br /&gt;
&lt;br /&gt;
* Creating a replica:&lt;br /&gt;
** Create a share instance on the database.&lt;br /&gt;
** Update the share instance ''replica_state'' to ''out_of_sync''.&lt;br /&gt;
** Cast a call to the scheduler to find an appropriate host to schedule the replica on.&lt;br /&gt;
** In the scheduler, find weighted host for the replica.&lt;br /&gt;
*** If host cannot be chosen, update the replica's ''status'' and ''replica_state'' on the Database to ''error''. Throw an exception.&lt;br /&gt;
** Cast the create_share_replica call to the driver based on the weighted host selection.&lt;br /&gt;
** Prior to invoking the driver's call, collate information regarding existing ''active'' replica instance, existing share access rules and the replica's share_server, pass these to the driver while invoking ''create_replica''.&lt;br /&gt;
** The driver may return ''export_locations'' and ''replica_state''. If they are returned, the database is updated with these values.&lt;br /&gt;
** If the ''replication_type'' is ''writable'', the driver MUST return the ''replica_state'' set to ''active''.&lt;br /&gt;
** All the access rules for the new replica are set to ''active'' state on the database.&lt;br /&gt;
** The driver may throw an exception, update the ''status'' and ''replica_state'' of the replica to ''error''.&lt;br /&gt;
&lt;br /&gt;
* Listing/showing shares:&lt;br /&gt;
** For shares that support replication, the result of listing/showing the share will have new fields, ''replication_type'': denoting the replication style supported and ''has_replicas'' to denote if the share has replicas.&lt;br /&gt;
** For replicated shares, the primary instance for the share must be preferred among those replicas that have a status ''replication_change'' or among those that have a replica_state set to ''active''.&lt;br /&gt;
&lt;br /&gt;
* Listing replicas&lt;br /&gt;
** For listing, Grab share instances from the database that have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** If share_id is provided, grab only share instances that belong to that share and have a replica_state among {''in_sync'', ''active'', ''out_of_sync'', ''error''}.&lt;br /&gt;
** Limits and offsets must be respected on the list calls.&lt;br /&gt;
&lt;br /&gt;
* Promoting a non-active replica:&lt;br /&gt;
** If replica is already active, do nothing.&lt;br /&gt;
** Update the ''status'' of the replica being promoted to ''replication_change''.&lt;br /&gt;
** Grab all available replicas and invoke the appropriate driver''s promote_replica call by passing the available replicas and the new replica.&lt;br /&gt;
** If the driver throws an exception at this stage, there is a good chance that the replicas are somehow altered on the backend. Loop through the replicas and set their ''replica_state''s to ''error'' and leave the ''status'' unchanged. Also set the ''status'' of the replica that failed to promote to ''available'' as before this operation. The backend may choose to update the actual replica_state during the replica monitoring call.&lt;br /&gt;
** The driver may return an updated list of replicas. Update the ''export_locations'' and ''replica_state''s to the database.&lt;br /&gt;
** The ''status'' of the replica that was promoted should return to ''available'' from ''replication_change''.&lt;br /&gt;
&lt;br /&gt;
* Periodic replica update:&lt;br /&gt;
** The share manager implements a looping call with default interval of 5 minutes to query from each driver and each backend the ''replica_state'' of all non-active replicas that are associated with them.&lt;br /&gt;
** The driver is allowed to set the ''replica_state'' to ''in_sync'', ''out_of_sync'', and in exceptional cases, ''error''.&lt;br /&gt;
** If the driver sets the ''replica_state'' of a replica to ''error'', it is assumed that some irrecoverable damage has occured to the replica instance. The ''status'' of the replica instance must be set to ''error'' as well.&lt;br /&gt;
&lt;br /&gt;
* Deleting a share replica&lt;br /&gt;
** If the replica had no host, it is simply removed from the database.&lt;br /&gt;
** The ''status'' of the replica is set to ''deleting'' on the database and the appropriate driver method is called to delete the replica.&lt;br /&gt;
** If the driver fails to delete the replica, the ''status'' of the replica is updated to ''error_deleting'' on the database.&lt;br /&gt;
** If the driver returns without errors, the replica instance is removed from the database.&lt;br /&gt;
&lt;br /&gt;
==Scheduler Impact==&lt;br /&gt;
* The host_manager must update the ''replication_type'' capability from the backend. The backends must report this capability at the host/pool level.&lt;br /&gt;
* The filter_scheduler must then match the ''replication_type'' capability with the capability that the replication share_type demands.&lt;br /&gt;
* The ''replication_type'' must be one of the styles mentioned [[#Supported Replication Styles|above]].&lt;br /&gt;
&lt;br /&gt;
==DB Impact==&lt;br /&gt;
* Share Export Locations:&lt;br /&gt;
Preferred export locations will only be from the instances with ''replica_state'' set to ''active''.&lt;br /&gt;
  def export_locations(self):&lt;br /&gt;
      # TODO(gouthamr): Return AZ specific export locations for replicated&lt;br /&gt;
      #  shares&lt;br /&gt;
      # NOTE(gouthamr): For a replicated share, export locations of the&lt;br /&gt;
      # 'active' instances are taken, if 'available'.&lt;br /&gt;
      all_export_locations = []&lt;br /&gt;
      select_instances = list(filter(&lt;br /&gt;
          lambda x: x['replica_state'] == constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
          self.instances)) or self.instances&lt;br /&gt;
      for instance in select_instances:&lt;br /&gt;
          if instance['status'] == constants.STATUS_AVAILABLE:&lt;br /&gt;
              for export_location in instance.export_locations:&lt;br /&gt;
                  all_export_locations.append(export_location['path'])&lt;br /&gt;
    return all_export_locations&lt;br /&gt;
&lt;br /&gt;
* Share Instance:&lt;br /&gt;
Preferred instance will be an instance with ''status'' set to ''replication_change'' or any instance with ''status'' set to ''available'' and ''replica_state'' set to ''active''.&lt;br /&gt;
  def instance(self):&lt;br /&gt;
   # NOTE(gouthamr): The order of preference: status 'replication_change',&lt;br /&gt;
   # followed  by 'available' and 'creating'. If replicated share and&lt;br /&gt;
   # not undergoing a 'replication_change', only 'active' instances are&lt;br /&gt;
   # preferred.&lt;br /&gt;
   result = None&lt;br /&gt;
   if len(self.instances) &amp;gt; 0:&lt;br /&gt;
       order = [constants.STATUS_REPLICATION_CHANGE,&lt;br /&gt;
                constants.STATUS_AVAILABLE, constants.STATUS_CREATING]&lt;br /&gt;
       other_statuses = ([x['status'] for x in self.instances&lt;br /&gt;
                          if x['status'] not in order])&lt;br /&gt;
       order.extend(other_statuses)&lt;br /&gt;
       sorted_instances = sorted(&lt;br /&gt;
           self.instances, key=lambda x: order.index(x['status']))&lt;br /&gt;
       select_instances = sorted_instances&lt;br /&gt;
       if (select_instances[0]['status'] !=&lt;br /&gt;
               constants.STATUS_REPLICATION_CHANGE):&lt;br /&gt;
           select_instances = (&lt;br /&gt;
               list(filter(lambda x: x['replica_state'] ==&lt;br /&gt;
                           constants.REPLICA_STATE_ACTIVE,&lt;br /&gt;
                           sorted_instances)) or sorted_instances&lt;br /&gt;
           )&lt;br /&gt;
       result = select_instances[0]&lt;br /&gt;
   return result&lt;br /&gt;
&lt;br /&gt;
* New field on Share:&lt;br /&gt;
  replication_type = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
* New field on ShareInstance&lt;br /&gt;
  replica_state = Column(String(255), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API Design==&lt;br /&gt;
  GET /share-replicas/&lt;br /&gt;
  GET /share-replicas?share-id=&amp;lt;share_id&amp;gt;&lt;br /&gt;
  GET /share-replicas/&amp;lt;replica_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  POST /share-replicas/&amp;lt;share-id&amp;gt;&lt;br /&gt;
  Body:&lt;br /&gt;
  {&lt;br /&gt;
    'share_replica':&lt;br /&gt;
    {&lt;br /&gt;
      'availability_zone':&amp;lt;availability_zone_id&amp;gt;,&lt;br /&gt;
      'share_id':&amp;lt;share_id&amp;gt;,&lt;br /&gt;
      'share_network_id':&amp;lt;share_network_id&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  POST /share-replicas/&amp;lt;replica-id&amp;gt;/action&lt;br /&gt;
  Body:&lt;br /&gt;
  {'os-promote_replica': null}&lt;br /&gt;
&lt;br /&gt;
  DELETE /share-replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
&lt;br /&gt;
policy.json - All replication group policies should default to the default policy&lt;br /&gt;
    &amp;quot;share_replica:get_all&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:show&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:create&amp;quot; : &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:delete&amp;quot;: &amp;quot;rule:default&amp;quot;,&lt;br /&gt;
    &amp;quot;share_replica:promote&amp;quot;: &amp;quot;rule:default&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
  def create_replica(self, context, active_replica, new_replica,&lt;br /&gt;
                   access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Replicate the active replica to a new replica on this backend.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              &amp;lt;models.ShareInstanceExportLocations&amp;gt;._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param new_replica: The share replica dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'out_of_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica being created.&lt;br /&gt;
      :return: (export_locations, replica_state)&lt;br /&gt;
      export_locations is a list of paths and replica_state is one of&lt;br /&gt;
      active, in-sync, out-of-sync or error.&lt;br /&gt;
      A backend supporting 'writable' type replication should return&lt;br /&gt;
      'active' as the replica_state.&lt;br /&gt;
      Export locations should be in the same format as returned by a&lt;br /&gt;
      share_create. This list may be empty or None.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
          .. code::&lt;br /&gt;
              [{'id': 'uuid', 'export_locations': ['export_path']}]&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def delete_replica(self, context, active_replica, replica,&lt;br /&gt;
                   share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Delete a replica.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param active_replica: A current active replica instance dictionary.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'active',&lt;br /&gt;
          'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param replica: Dictionary of the share replica being deleted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be deleted.&lt;br /&gt;
      :return: None.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def promote_replica(self, context, replica_list, replica, access_rules, share_server=None):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Promote a replica to 'active' replica state.&lt;br /&gt;
      :param context:Current context&lt;br /&gt;
      :param replica_list: List of all replicas for a particular share.&lt;br /&gt;
      This list also contains the replica to be promoted. The 'active'&lt;br /&gt;
      replica will have its 'replica_state' attr set to 'active'.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          [&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'active',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              {&lt;br /&gt;
              'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
              'replica_state': 'in-sync',&lt;br /&gt;
                  ...&lt;br /&gt;
              'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
              'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
              },&lt;br /&gt;
              ...&lt;br /&gt;
          ]&lt;br /&gt;
      :param replica: Dictionary of the replica to be promoted.&lt;br /&gt;
          EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
          {&lt;br /&gt;
          'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'deleted': False,&lt;br /&gt;
          'host': 'openstack2@cmodeSSVMNFS2',&lt;br /&gt;
          'status': 'available',&lt;br /&gt;
          'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
          'terminated_at': None,&lt;br /&gt;
          'replica_state': 'in_sync',&lt;br /&gt;
          'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'export_locations': [&lt;br /&gt;
              models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
          ],&lt;br /&gt;
          'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
          'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',&lt;br /&gt;
          'share_server': &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
          }&lt;br /&gt;
      :param access_rules: A list of access rules that other instances of&lt;br /&gt;
      the share already obey.&lt;br /&gt;
      EXAMPLE:&lt;br /&gt;
           .. code::&lt;br /&gt;
           [ {&lt;br /&gt;
           'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',&lt;br /&gt;
           'deleted' = False,&lt;br /&gt;
           'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
           'access_type' = 'ip',&lt;br /&gt;
           'access_to' = '172.16.20.1',&lt;br /&gt;
           'access_level' = 'rw',&lt;br /&gt;
           }]&lt;br /&gt;
      :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None,&lt;br /&gt;
      Share server of the replica to be promoted.&lt;br /&gt;
      :return: updated_replica_list or None&lt;br /&gt;
          The driver can return the updated list as in the request&lt;br /&gt;
          parameter. Changes that will be updated to the Database are:&lt;br /&gt;
          'export_locations' and 'replica_state'.&lt;br /&gt;
      :raises Exception&lt;br /&gt;
          This can be any exception derived from BaseException. This is&lt;br /&gt;
          re-raised by the manager after some necessary cleanup. If the&lt;br /&gt;
          driver raises an exception during promotion, it is assumed&lt;br /&gt;
          that all of the replicas of the share are in an inconsistent&lt;br /&gt;
          state. Recovery is only possible through the periodic update&lt;br /&gt;
          call and/or administrator intervention to correct the 'status'&lt;br /&gt;
          of the affected replicas if they become healthy again.&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      def update_replica_status(self, context, replica, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Update the status and replica_state of a replica.&lt;br /&gt;
        Drivers should fix replication relationships that were broken if&lt;br /&gt;
        possible inside this method.&lt;br /&gt;
        :param context:Current context&lt;br /&gt;
        :param replica: Dictionary of the replica being updated.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
             .. code::&lt;br /&gt;
            {&lt;br /&gt;
            'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',&lt;br /&gt;
            'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'deleted': False,&lt;br /&gt;
            'host': 'openstack2@cmodeSSVMNFS1',&lt;br /&gt;
            'status': 'available',&lt;br /&gt;
            'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
            'terminated_at': None,&lt;br /&gt;
            'replica_state': 'active',&lt;br /&gt;
            'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',&lt;br /&gt;
            'export_locations': [&lt;br /&gt;
                models.ShareInstanceExportLocations._as_dict()&lt;br /&gt;
            ],&lt;br /&gt;
            'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',&lt;br /&gt;
            'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',&lt;br /&gt;
            }&lt;br /&gt;
        :param share_server: &amp;lt;models.ShareServer&amp;gt;._as_dict() or None&lt;br /&gt;
        :return: replica_state&lt;br /&gt;
            replica_state - a str value denoting the replica_state that the&lt;br /&gt;
            replica can have. Valid values are 'in_sync' and 'out_of_sync'&lt;br /&gt;
            or None (to leave the current replica_state unchanged).&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
==Manila Client==&lt;br /&gt;
    share-replica-create Creates a replica&lt;br /&gt;
    share-replica-delete Remove one or more share replicas.&lt;br /&gt;
    share-replica-list  List share replicas.&lt;br /&gt;
    share-replica-promote Promote replica to active replica.&lt;br /&gt;
    share-replica-show  Show details about a replica.&lt;br /&gt;
&lt;br /&gt;
=FAQs=&lt;br /&gt;
# '''How do we deal with Network issues in multi-SVM replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;If we choose to make replication a single-svm-only feature, the share-network API doesn't need to change. In order to support replication with share-networks, we also need to modify the share-network create API which allows creation of share networks with a table of AZ-to-subnet mappings. This approach allows us to keep a single share-network per share (with associated security service) while allowing the tenant to specify enough information that each share instance can be attached to the appropriate network in each AZ. Multi-AZ share networks would also be useful for non-replicated use cases.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we support Pool-level Replication?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Some vendors have suggested that certain backends can mirror groups of shares or whole pools more efficiently than individual shares. This design only addresses the mirroring of individual shares. In the future, we may allow allow replication of groups of shares, but only if those groups are contained within a single tenant and defined by the tenant.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''From where to where do we allow replication? Is it intra-cloud or inter-cloud? Do we allow replication to something that's not managed by Manila?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;Intra-cloud. Replicating to something outside of Manila allows a bit more freedom, but with significantly less value, because there's practically nothing we can do to automate the failover/failback portion of a disaster. For use cases involving replication outside of Manila, we would need to involve other tools with more breadth/scope to manage the process.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Who configures the replication? The admin? The end user? The manila scheduler?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;The end user. In the original design we presumed that the actual replication relationships should be hidden from the end user, but this doesn't match well with the concept of AZs that we are adding to Manila. If the users need to have control over which AZ the primary copy of their data lives in, then they also need to control where the other copies live. This means that the administrator's job is to ensure that for any share type that is replicated, it can be replicated from any AZ to any other AZ.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Is replication supported only intra-region or inter-region as well? How about intra-AZ vs inter-AZ?''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This design is for intra-region only. Inter-region replication is clearly a feature we want, but it would look pretty different from intra-region replication; this design does not cover that. Intra-AZ replication is supported, however inter-AZ replication is recommended as AZs should be perceived as failure domains.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Unanswered Questions=&lt;br /&gt;
# '''Is there no way to achieve non-disruptive failover?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(bswartz) I would love to find out that our initial intuition here is wrong, because it would change a lot of aspects of the design. It's worth spending time to brainstorm and research possibilities in this area. So far the most promising ideas involve:&lt;br /&gt;
#*Using VirtFS to mediate filesystem access and achieving non-disruptive failover that way&lt;br /&gt;
#*Using some kind of agent inside the guests to mediate file access&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Can a replica have a different share_type? There is a valid use case where a user would want to create a share replica on backend with different capabilities than the one the original share resides on. For instance, replicas might need to be on a less expensive backend. In that case, can the replica have a different share_type altogether?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;quot;Currently&amp;quot;, we inherit the share_type of the share and believe that replication has to be on symmetric terms, where both backends have similar capabilities.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''Can we allow the driver to restrict replication support between available backends? Backends may support replication to other compatible backends only. Hence, they must report some sort of information to the scheduler so that when creating a replica for an existing share, the scheduler would use that information to schedule the creation of the replica. What information should this be?'''   &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) We're investigating including 'driver_class_name' in a ReplicationFilter, including the possibility of backend reported configuration, 'replication_partners'.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How are access rules persisted across replicas/share instances?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#*Do all replicas have the same access rules applied? (gouthamr): This is Currently being pursued&lt;br /&gt;
#*Should access rules be applied only to &amp;quot;active&amp;quot; replicas?&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
#'''How does migration affect replicated shares?'''&lt;br /&gt;
#*(gouthamr)In the Tokyo summit, it was decided that we currently disallow migration of a share that has replicas. The replication relationships must be broken and reestablished after the migration is complete in order to migrate a share with replicas.&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''Do we need an API to initiate a sync? (resync or force-update)''' &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;This is a great idea and one certain use case is during planned failovers. (gouthamr)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
# '''How to recover from promotion failures?'''&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;(gouthamr) Currently, if some exception occurs at the driver level, the replicas are rendered useless. Should we provide escape hatches to avoid complete loss in case these are recoverable exceptions? The administrator has the ability to 'reset-state' and affect the 'status' of any replica. Currently, there exists no API to 'reset-replica-state' for a replica.&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
These examples assume that the replicas exist in different AZs.&lt;br /&gt;
&lt;br /&gt;
== Writable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=writeable&lt;br /&gt;
# Administrator creates a new share_type called foo&lt;br /&gt;
# Administrator sets replication_type=writeable extra spec on share type foo&lt;br /&gt;
# User creates new share of type foo in AZ b1&lt;br /&gt;
# Share is created with replication_type=writeable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to active (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 writes some data to the share, which is immediately visible to client1&lt;br /&gt;
&lt;br /&gt;
== Readable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication_type=readable&lt;br /&gt;
# Administrator creates a new share_type called bar&lt;br /&gt;
# Administrator sets replication_type=readable extra spec on share type bar&lt;br /&gt;
# User creates new share of type bar in AZ b1&lt;br /&gt;
# Share is created with replication_type=readable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to in_sync (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 cannot write data to the share but continues to see updates&lt;br /&gt;
&lt;br /&gt;
== Failover/failback example ==&lt;br /&gt;
&lt;br /&gt;
(Continued from above)&lt;br /&gt;
# An outage occurs in AZ b1&lt;br /&gt;
# Administrator sends out a bulletin about the outage to his users &amp;quot;the power transformer in b1 turned to slag, it will be 12 hours before it can be replaced, please bear with us, yada yada&amp;quot;&lt;br /&gt;
# User notices that his application on client1 is no longer running, and investigates&lt;br /&gt;
# User finds out that client1 is gone, and reads a bulletin from the admin explaining why&lt;br /&gt;
# User notes that the b1 replica is his share is still active and the b2 replica is in_sync, while the state of the share is available&lt;br /&gt;
# User calls set active replica to AZ b2 on his share&lt;br /&gt;
# The share goes to state replication_change and access to the share is briefly lost on client2&lt;br /&gt;
# The state of replica b2 changes to active and the state of replica b1 changes to out_of_sync after Manila fails to contact the original primary. The state of the share changes back to available, and access is restored on client2&lt;br /&gt;
# User starts his application on client2, and the application recovers from an apparent crash, with a consistent copy of the application's data&lt;br /&gt;
# User application is back up and running, disaster is averted&lt;br /&gt;
# Eventually maintenance on the b1 AZ is completed, and all of the equipment is reactivated&lt;br /&gt;
# Administrator sends out a bulletin to his users about the outage ending &amp;quot;we replaced the transformer with a better one, everything is back online, thanks for your understanding, yada yada&amp;quot;&lt;br /&gt;
# Manila notices the out_of_sync replica is reachable and initiates a resync, bringing the b1 replica in_sync within a short time&lt;br /&gt;
# After some time, the users reads the bulletin and observes that his share is being replicated again. He decides to intentionally move back to b1.&lt;br /&gt;
# User gracefully shuts down his application, and flushes I/O&lt;br /&gt;
# User calls set active replica to AZ b1 on his share&lt;br /&gt;
# The share goes to state replication_change and no disruption is observed because the application is shut down&lt;br /&gt;
# The state of replica b1 changes to active and the state of replica b2 changes to in_sync after Manila reverses the replication again. The state of the share changes back to available&lt;br /&gt;
# User starts his application on client1, and the application starts cleanly, having been shut down gracefully&lt;br /&gt;
&lt;br /&gt;
=Implementation Progress=&lt;br /&gt;
===Core Work===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manila-share-replication Blueprint for Core API/Scheduler implementation]&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/manilaclient-share-replication Blueprint for Client implementation]&lt;br /&gt;
&lt;br /&gt;
===Ex Driver Implementation===&lt;br /&gt;
  [https://blueprints.launchpad.net/manila/+spec/netapp-cdot-single-svm-replication Blueprint for cDOT Driver Implementation]&lt;br /&gt;
&lt;br /&gt;
=Older Design Pages=&lt;br /&gt;
* Replication Use Cases: https://wiki.openstack.org/wiki/Manila/Replication_Use_Cases&lt;br /&gt;
* Design Notes: https://wiki.openstack.org/wiki/Manila/Replication_Design_Notes&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=96589</id>
		<title>Manila/Meetings</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=96589"/>
				<updated>2015-11-12T14:32:49Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Next meeting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Weekly Manila team meeting =&lt;br /&gt;
'''NOTE MEETING TIME: Thursday at 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
If you're interested in management of shared filesystems for OpenStack, we have a weekly meetings in &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#openstack-meeting-alt&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, on Thursdays at 15:00 UTC.  Please feel free to add items to the agenda below.  NOTE: When adding topics please include your IRC name so we know who's topic it is and how to get more info.&lt;br /&gt;
&lt;br /&gt;
== Next meeting ==&lt;br /&gt;
'''NOTE:''' ''Include your IRC nickname next to agenda items so that you can be called upon in the meeting and arrive at the meeting promptly if placing items in agenda. You might want to put this on your calendar if you are adding items.''&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' USA-based attendees should remember to double check the meeting time as the end of daylight savings time will move the meeting earlier in your day.&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 12 Nov, 2015, 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
# Which method is better for Manila QoS(independent way or just use extra specs )&lt;br /&gt;
#* link:http://paste.openstack.org/show/477677/ &lt;br /&gt;
#*If use extra specs to config QoS, Does we first need add “QoS_support=true/false” in share_type. Does we need to add QoS_support flag in common capabilities(https://github.com/openstack/manila/blob/master/doc/source/devref/capabilities_and_extra_specs.rst)?&lt;br /&gt;
 eg:  share_type: qos_support='&amp;lt;is&amp;gt; True' or '&amp;lt;is&amp;gt; False' &lt;br /&gt;
                            netapp:max_iops=100  or qos:netapp:max_iops=100 or qos:max_iops=100&lt;br /&gt;
        driver update: qos_support=true&lt;br /&gt;
#** An alternative could be to have the driver report a range&lt;br /&gt;
&lt;br /&gt;
# Manila DR update&lt;br /&gt;
#* Still no reviews on https://review.openstack.org/#/c/238572/&lt;br /&gt;
#* First-party driver implementation? Which driver, current generic or new solution? When do we need this implemented and who wants to do it?&lt;br /&gt;
#* Replication_change share state - This is the state of the share when any of it's replicas are being promoted. Is 'replication_change' good or is there a better phrase?&lt;br /&gt;
# Manila Driver minimum requirements document update (ganso)&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
== Previous meetings ==&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 5 Nov, 2015, 15:00 UTC'''&lt;br /&gt;
# Decide on read-only access rules as a required feature&lt;br /&gt;
# Manila DR - Design/Code feedback (gouthamr) &lt;br /&gt;
#* [https://wiki.openstack.org/wiki/Manila/design/manila-mitaka-data-replication Design Document]&lt;br /&gt;
#* [https://review.openstack.org/#/c/238572/ Core Implementation on Gerrit]&lt;br /&gt;
#* [https://review.openstack.org/#/c/235448/ Client Implementation on Gerrit]&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 1 Oct, 2015, 15:00 UTC'''&lt;br /&gt;
# Liberty RC2 status&lt;br /&gt;
#* https://launchpad.net/manila/+milestone/liberty-rc2&lt;br /&gt;
#* https://review.openstack.org/#/q/project:openstack/manila+branch:stable/liberty,n,z&lt;br /&gt;
# Mitaka Design Summit&lt;br /&gt;
#* https://etherpad.openstack.org/p/manila-mitaka-summit-topics&lt;br /&gt;
# Vendor driver docs&lt;br /&gt;
#* https://github.com/openstack/manila/blob/master/doc/source/devref/share_back_ends_feature_support_mapping.rst&lt;br /&gt;
# Manila Client Nova Style Microversion Support (cfouts)&lt;br /&gt;
#* https://review.openstack.org/#/c/229142/&lt;br /&gt;
#* http://docs.openstack.org/developer/manila/devref/api_microversion_dev.html&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 24 Sep, 2015, 15:00 UTC'''&lt;br /&gt;
# 3rd-party CI status&lt;br /&gt;
#* http://ec2-54-67-102-119.us-west-1.compute.amazonaws.com:5000/?project=openstack/manila&amp;amp;user=&amp;amp;timeframe=72&amp;amp;start=&amp;amp;end=&amp;amp;page_size=500&lt;br /&gt;
#* http://ci-watch.tintri.com/project?project=manila&lt;br /&gt;
# Liberty RC status&lt;br /&gt;
# Support for QoS in Manila (zhongjun2)&lt;br /&gt;
#* https://blueprints.launchpad.net/manila/+spec/manila-support-qos&lt;br /&gt;
#* https://wiki.openstack.org/wiki/Manila/QoS&lt;br /&gt;
# Reminder for backend driver maintainers to update feature support table (toabctl)&lt;br /&gt;
#* http://docs.openstack.org/developer/manila/devref/share_back_ends_feature_support_mapping.html&lt;br /&gt;
# Regression when using NetApp - license issue with netapp_lib (toabctl)&lt;br /&gt;
#* https://bugs.launchpad.net/cinder/+bug/1499334&lt;br /&gt;
# Mitaka Design Summit&lt;br /&gt;
#* Propose topics - https://etherpad.openstack.org/p/manila-mitaka-summit-topics&lt;br /&gt;
# Vendor driver docs&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
http://eavesdrop.openstack.org/meetings/manila/&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=96552</id>
		<title>Manila/Meetings</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=96552"/>
				<updated>2015-11-12T13:08:25Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Next meeting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Weekly Manila team meeting =&lt;br /&gt;
'''NOTE MEETING TIME: Thursday at 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
If you're interested in management of shared filesystems for OpenStack, we have a weekly meetings in &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#openstack-meeting-alt&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, on Thursdays at 15:00 UTC.  Please feel free to add items to the agenda below.  NOTE: When adding topics please include your IRC name so we know who's topic it is and how to get more info.&lt;br /&gt;
&lt;br /&gt;
== Next meeting ==&lt;br /&gt;
'''NOTE:''' ''Include your IRC nickname next to agenda items so that you can be called upon in the meeting and arrive at the meeting promptly if placing items in agenda. You might want to put this on your calendar if you are adding items.''&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' USA-based attendees should remember to double check the meeting time as the end of daylight savings time will move the meeting earlier in your day.&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 12 Nov, 2015, 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
# Which method is better for Manila QoS(independent way or just use extra specs )&lt;br /&gt;
#* link:http://paste.openstack.org/show/477677/ &lt;br /&gt;
#*If use extra specs to config QoS, Does we first need add “QoS_support=true/false” in share_type. Does we need to add QoS_support flag in common capabilities?&lt;br /&gt;
# Manila DR update&lt;br /&gt;
#* Still no reviews on https://review.openstack.org/#/c/238572/&lt;br /&gt;
#* First-party driver implementation? Which driver, current generic or new solution? When do we need this implemented and who wants to do it?&lt;br /&gt;
#* Replication_change share state - This is the state of the share when any of it's replicas are being promoted. Is 'replication_change' good or is there a better phrase?&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
== Previous meetings ==&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 5 Nov, 2015, 15:00 UTC'''&lt;br /&gt;
# Decide on read-only access rules as a required feature&lt;br /&gt;
# Manila DR - Design/Code feedback (gouthamr) &lt;br /&gt;
#* [https://wiki.openstack.org/wiki/Manila/design/manila-mitaka-data-replication Design Document]&lt;br /&gt;
#* [https://review.openstack.org/#/c/238572/ Core Implementation on Gerrit]&lt;br /&gt;
#* [https://review.openstack.org/#/c/235448/ Client Implementation on Gerrit]&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 1 Oct, 2015, 15:00 UTC'''&lt;br /&gt;
# Liberty RC2 status&lt;br /&gt;
#* https://launchpad.net/manila/+milestone/liberty-rc2&lt;br /&gt;
#* https://review.openstack.org/#/q/project:openstack/manila+branch:stable/liberty,n,z&lt;br /&gt;
# Mitaka Design Summit&lt;br /&gt;
#* https://etherpad.openstack.org/p/manila-mitaka-summit-topics&lt;br /&gt;
# Vendor driver docs&lt;br /&gt;
#* https://github.com/openstack/manila/blob/master/doc/source/devref/share_back_ends_feature_support_mapping.rst&lt;br /&gt;
# Manila Client Nova Style Microversion Support (cfouts)&lt;br /&gt;
#* https://review.openstack.org/#/c/229142/&lt;br /&gt;
#* http://docs.openstack.org/developer/manila/devref/api_microversion_dev.html&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 24 Sep, 2015, 15:00 UTC'''&lt;br /&gt;
# 3rd-party CI status&lt;br /&gt;
#* http://ec2-54-67-102-119.us-west-1.compute.amazonaws.com:5000/?project=openstack/manila&amp;amp;user=&amp;amp;timeframe=72&amp;amp;start=&amp;amp;end=&amp;amp;page_size=500&lt;br /&gt;
#* http://ci-watch.tintri.com/project?project=manila&lt;br /&gt;
# Liberty RC status&lt;br /&gt;
# Support for QoS in Manila (zhongjun2)&lt;br /&gt;
#* https://blueprints.launchpad.net/manila/+spec/manila-support-qos&lt;br /&gt;
#* https://wiki.openstack.org/wiki/Manila/QoS&lt;br /&gt;
# Reminder for backend driver maintainers to update feature support table (toabctl)&lt;br /&gt;
#* http://docs.openstack.org/developer/manila/devref/share_back_ends_feature_support_mapping.html&lt;br /&gt;
# Regression when using NetApp - license issue with netapp_lib (toabctl)&lt;br /&gt;
#* https://bugs.launchpad.net/cinder/+bug/1499334&lt;br /&gt;
# Mitaka Design Summit&lt;br /&gt;
#* Propose topics - https://etherpad.openstack.org/p/manila-mitaka-summit-topics&lt;br /&gt;
# Vendor driver docs&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
http://eavesdrop.openstack.org/meetings/manila/&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=96550</id>
		<title>Manila/Meetings</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=96550"/>
				<updated>2015-11-12T12:53:52Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Next meeting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Weekly Manila team meeting =&lt;br /&gt;
'''NOTE MEETING TIME: Thursday at 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
If you're interested in management of shared filesystems for OpenStack, we have a weekly meetings in &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#openstack-meeting-alt&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, on Thursdays at 15:00 UTC.  Please feel free to add items to the agenda below.  NOTE: When adding topics please include your IRC name so we know who's topic it is and how to get more info.&lt;br /&gt;
&lt;br /&gt;
== Next meeting ==&lt;br /&gt;
'''NOTE:''' ''Include your IRC nickname next to agenda items so that you can be called upon in the meeting and arrive at the meeting promptly if placing items in agenda. You might want to put this on your calendar if you are adding items.''&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' USA-based attendees should remember to double check the meeting time as the end of daylight savings time will move the meeting earlier in your day.&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 12 Nov, 2015, 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
# Which method is better for Manila QoS(independent way or just use extra specs )&lt;br /&gt;
#* link:http://paste.openstack.org/show/477677/ &lt;br /&gt;
#*If use extra specs to config QoS, Does we first need add “QoS_support=true/false” in share_type. Does we need to add QoS_support flag in common capabilities?&lt;br /&gt;
# Manila DR update&lt;br /&gt;
#* Still no reviews on https://review.openstack.org/#/c/238572/&lt;br /&gt;
#* First-party driver implementation? Which driver, current generic or new solution? When do we need this implemented and who wants to do it?&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
== Previous meetings ==&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 5 Nov, 2015, 15:00 UTC'''&lt;br /&gt;
# Decide on read-only access rules as a required feature&lt;br /&gt;
# Manila DR - Design/Code feedback (gouthamr) &lt;br /&gt;
#* [https://wiki.openstack.org/wiki/Manila/design/manila-mitaka-data-replication Design Document]&lt;br /&gt;
#* [https://review.openstack.org/#/c/238572/ Core Implementation on Gerrit]&lt;br /&gt;
#* [https://review.openstack.org/#/c/235448/ Client Implementation on Gerrit]&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 1 Oct, 2015, 15:00 UTC'''&lt;br /&gt;
# Liberty RC2 status&lt;br /&gt;
#* https://launchpad.net/manila/+milestone/liberty-rc2&lt;br /&gt;
#* https://review.openstack.org/#/q/project:openstack/manila+branch:stable/liberty,n,z&lt;br /&gt;
# Mitaka Design Summit&lt;br /&gt;
#* https://etherpad.openstack.org/p/manila-mitaka-summit-topics&lt;br /&gt;
# Vendor driver docs&lt;br /&gt;
#* https://github.com/openstack/manila/blob/master/doc/source/devref/share_back_ends_feature_support_mapping.rst&lt;br /&gt;
# Manila Client Nova Style Microversion Support (cfouts)&lt;br /&gt;
#* https://review.openstack.org/#/c/229142/&lt;br /&gt;
#* http://docs.openstack.org/developer/manila/devref/api_microversion_dev.html&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 24 Sep, 2015, 15:00 UTC'''&lt;br /&gt;
# 3rd-party CI status&lt;br /&gt;
#* http://ec2-54-67-102-119.us-west-1.compute.amazonaws.com:5000/?project=openstack/manila&amp;amp;user=&amp;amp;timeframe=72&amp;amp;start=&amp;amp;end=&amp;amp;page_size=500&lt;br /&gt;
#* http://ci-watch.tintri.com/project?project=manila&lt;br /&gt;
# Liberty RC status&lt;br /&gt;
# Support for QoS in Manila (zhongjun2)&lt;br /&gt;
#* https://blueprints.launchpad.net/manila/+spec/manila-support-qos&lt;br /&gt;
#* https://wiki.openstack.org/wiki/Manila/QoS&lt;br /&gt;
# Reminder for backend driver maintainers to update feature support table (toabctl)&lt;br /&gt;
#* http://docs.openstack.org/developer/manila/devref/share_back_ends_feature_support_mapping.html&lt;br /&gt;
# Regression when using NetApp - license issue with netapp_lib (toabctl)&lt;br /&gt;
#* https://bugs.launchpad.net/cinder/+bug/1499334&lt;br /&gt;
# Mitaka Design Summit&lt;br /&gt;
#* Propose topics - https://etherpad.openstack.org/p/manila-mitaka-summit-topics&lt;br /&gt;
# Vendor driver docs&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
http://eavesdrop.openstack.org/meetings/manila/&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=96549</id>
		<title>Manila/Meetings</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=96549"/>
				<updated>2015-11-12T12:51:09Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Weekly Manila team meeting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Weekly Manila team meeting =&lt;br /&gt;
'''NOTE MEETING TIME: Thursday at 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
If you're interested in management of shared filesystems for OpenStack, we have a weekly meetings in &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#openstack-meeting-alt&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, on Thursdays at 15:00 UTC.  Please feel free to add items to the agenda below.  NOTE: When adding topics please include your IRC name so we know who's topic it is and how to get more info.&lt;br /&gt;
&lt;br /&gt;
== Next meeting ==&lt;br /&gt;
'''NOTE:''' ''Include your IRC nickname next to agenda items so that you can be called upon in the meeting and arrive at the meeting promptly if placing items in agenda. You might want to put this on your calendar if you are adding items.''&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' USA-based attendees should remember to double check the meeting time as the end of daylight savings time will move the meeting earlier in your day.&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 12 Nov, 2015, 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
# Which method is better for Manila QoS(independent way or just use extra specs )&lt;br /&gt;
#* link:http://paste.openstack.org/show/477677/ &lt;br /&gt;
#*If use extra specs to config QoS, Does we first need add “QoS_support=true/false” in share_type. Does we need to add QoS_support flag in common capabilities?&lt;br /&gt;
# Manila DR update&lt;br /&gt;
#* First-party driver implementation? Which driver, current generic or new solution? When do we need this implemented and who wants to do it?&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
== Previous meetings ==&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 5 Nov, 2015, 15:00 UTC'''&lt;br /&gt;
# Decide on read-only access rules as a required feature&lt;br /&gt;
# Manila DR - Design/Code feedback (gouthamr) &lt;br /&gt;
#* [https://wiki.openstack.org/wiki/Manila/design/manila-mitaka-data-replication Design Document]&lt;br /&gt;
#* [https://review.openstack.org/#/c/238572/ Core Implementation on Gerrit]&lt;br /&gt;
#* [https://review.openstack.org/#/c/235448/ Client Implementation on Gerrit]&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 1 Oct, 2015, 15:00 UTC'''&lt;br /&gt;
# Liberty RC2 status&lt;br /&gt;
#* https://launchpad.net/manila/+milestone/liberty-rc2&lt;br /&gt;
#* https://review.openstack.org/#/q/project:openstack/manila+branch:stable/liberty,n,z&lt;br /&gt;
# Mitaka Design Summit&lt;br /&gt;
#* https://etherpad.openstack.org/p/manila-mitaka-summit-topics&lt;br /&gt;
# Vendor driver docs&lt;br /&gt;
#* https://github.com/openstack/manila/blob/master/doc/source/devref/share_back_ends_feature_support_mapping.rst&lt;br /&gt;
# Manila Client Nova Style Microversion Support (cfouts)&lt;br /&gt;
#* https://review.openstack.org/#/c/229142/&lt;br /&gt;
#* http://docs.openstack.org/developer/manila/devref/api_microversion_dev.html&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 24 Sep, 2015, 15:00 UTC'''&lt;br /&gt;
# 3rd-party CI status&lt;br /&gt;
#* http://ec2-54-67-102-119.us-west-1.compute.amazonaws.com:5000/?project=openstack/manila&amp;amp;user=&amp;amp;timeframe=72&amp;amp;start=&amp;amp;end=&amp;amp;page_size=500&lt;br /&gt;
#* http://ci-watch.tintri.com/project?project=manila&lt;br /&gt;
# Liberty RC status&lt;br /&gt;
# Support for QoS in Manila (zhongjun2)&lt;br /&gt;
#* https://blueprints.launchpad.net/manila/+spec/manila-support-qos&lt;br /&gt;
#* https://wiki.openstack.org/wiki/Manila/QoS&lt;br /&gt;
# Reminder for backend driver maintainers to update feature support table (toabctl)&lt;br /&gt;
#* http://docs.openstack.org/developer/manila/devref/share_back_ends_feature_support_mapping.html&lt;br /&gt;
# Regression when using NetApp - license issue with netapp_lib (toabctl)&lt;br /&gt;
#* https://bugs.launchpad.net/cinder/+bug/1499334&lt;br /&gt;
# Mitaka Design Summit&lt;br /&gt;
#* Propose topics - https://etherpad.openstack.org/p/manila-mitaka-summit-topics&lt;br /&gt;
# Vendor driver docs&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
http://eavesdrop.openstack.org/meetings/manila/&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_FC_CI&amp;diff=92103</id>
		<title>ThirdPartySystems/NetApp FC CI</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_FC_CI&amp;diff=92103"/>
				<updated>2015-10-09T14:17:35Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ThirdPartySystemInfo|name=NetApp FC CI&lt;br /&gt;
|account=netapp-fc-ci&lt;br /&gt;
|contact= xdl-openstack-jenkins@netapp.com, andrew.kerr@netapp.com (akerr), alex.meade@netapp.com (ameade)&lt;br /&gt;
|intent=Test Openstack with NetApp Fibre Channel Cinder drivers using storage arrays&lt;br /&gt;
|structure=Nodepool, Zuul, Jenkins, modified upstream components with local configuration&lt;br /&gt;
|method=Using Zuul to connect to Gerrit&lt;br /&gt;
|programs=Cinder&lt;br /&gt;
|status= transitioning to be merged with the 'netapp-ci' system}}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/Replication_Use_Cases&amp;diff=91952</id>
		<title>Manila/Replication Use Cases</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/Replication_Use_Cases&amp;diff=91952"/>
				<updated>2015-10-07T18:56:26Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Unanswered Questions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Answered Questions ==&lt;br /&gt;
&lt;br /&gt;
Q: From where to where do we allow replication? Is it intra-cloud or inter-cloud? Do we allow replication to something that's not managed by Manila?&lt;br /&gt;
&lt;br /&gt;
A: Intra-cloud. Replicating to something outside of Manila allows a bit more freedom, but with significantly less value, because there's practically nothing we can do to automate the failover/failback portion of a disaster. For use cases involving replication outside of Manila, we would need to involve other tools with more breadth/scope to manage the process.&lt;br /&gt;
&lt;br /&gt;
Q: Do we support unplanned failovers? Do we support planned failovers? Are failovers disruptive or not?&lt;br /&gt;
&lt;br /&gt;
A: Failovers can be planned or unplanned, but they are always disruptive at the data level. With application integration, they could be made nondisruptive at the application level, but unfortunately we've chosen no to use any intermediary technology (like virtfs) in the data path, which means we have no options for non disruptive failovers.&lt;br /&gt;
&lt;br /&gt;
Q: Who configures the replication? The admin? The end user? The manila scheduler?&lt;br /&gt;
&lt;br /&gt;
A: The end user. In the original design we presumed that the actual replication relationships should be hidden from the end user, but this doesn't match well with the concept of AZs that we are adding to Manila. If the users need to have control over which AZ the primary copy of their data lives in, then they also need to control where the other copies live. This means that the administrator's job is to ensure that for any share type that is replicated, it can be replicated from any AZ to any other AZ.&lt;br /&gt;
&lt;br /&gt;
Q: Who triggers a failover? Is it a manual button the admin presses? Can Manila failover automatically? If so, when? Can the end users control failovers at all?&lt;br /&gt;
&lt;br /&gt;
A: Failovers are manual, triggered by either an administrator or a user. Generally speaking it's more appropriate for the administrator to initiate a failover because the administrator has more knowledge about the nature of an outage. However, it's also essential for end users to test failovers so they need the capability to initiate failovers of shares themselves.&lt;br /&gt;
&lt;br /&gt;
Q: During replication (before failover) is the secondary even visible/accessible?&lt;br /&gt;
&lt;br /&gt;
A: Yes, but possibly with significant limitations. Some backends may not support accessing the secondary side of a replicated share. Some backends may allow access, but read-only. We know of at least one backend that can support write access to the secondary (in which case calling it a secondary isn't really accurate because it's more of an active-active relationship). Amazon's EFS has the model of active-active replication so it's something we don't want to disallow.&lt;br /&gt;
&lt;br /&gt;
Q: What is the granularity of the failover? Whole backend? Single pools?&lt;br /&gt;
&lt;br /&gt;
A: Individual shares. There's no technical reason to prevent failover/failback on share-by-share basis. To make the administrator's life easier, we also have to support whole-backend failover (could be essential to minimize downtime in an actual disaster). The ability to do single-share failover is nice because it allows testing of the DR system without triggering an outage that affects users, since failovers are disruptive.&lt;br /&gt;
&lt;br /&gt;
== Unanswered Questions ==&lt;br /&gt;
&lt;br /&gt;
There are some major unanswered questions (or areas of investigation).&lt;br /&gt;
&lt;br /&gt;
1) Is there no way to achieve nondisruptive failover? I would love to find out that our initial intuition here is wrong, because it would change a lot of aspects of the design. It's worth spending time to brainstorm and research possibilities in this area. So far the most promising ideas involve:&lt;br /&gt;
* Using VirtFS to mediate filesystem access and achieving non-disruptive failover that way&lt;br /&gt;
* Using some kind of agent inside the guests to mediate file access&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) How do we deal with recovery after a disaster and failover? Assuming a successful failover, and a repair of the original primary, failing back will cause another outage. How can we orchestrate that to minimize pain and suffering?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Assuming the disruptive aspect of failovers is unavoidable, how can we invest to make them less painful at the application level?&lt;br /&gt;
Application quiescing and mount automation could make failovers nondisruptive for a least a select few applications.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4) Can the replica have a different share_type?&lt;br /&gt;
&lt;br /&gt;
There is a valid use case where a user would want to create a share replica on backend with different capabilities than the one the original share resides on. For instance, replicas might need to be on a less expensive backend. In that case, can the replica have a different share_type altogether?&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Currently&amp;quot;, we inherit the share_type of the share and believe that replication has to be on symmetric terms, where both backends have similar capabilities.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
5) Can we allow the driver to restrict replication support between available backends?&lt;br /&gt;
&lt;br /&gt;
Backends may support replication to other compatible backends only.  Hence, they must report some sort of information to the scheduler so that when creating a replica for an existing share, the scheduler would use that information to schedule the creation of the replica. What information should this be?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
6) How are access rules persisted across replicas/share instances?&lt;br /&gt;
* Do all replicas have the same access rules applied?  ''(Currently being pursued)''&lt;br /&gt;
* Should access rules be applied only to &amp;quot;active&amp;quot; replicas?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
7) How does migration affect replicated shares?&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
8)  API Endpoints:&lt;br /&gt;
* Current Endpoint Design: https://wiki.openstack.org/wiki/Manila/Replication_API_Design#New_APIs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
9) What export locations should appear when showing a replicated share?&lt;br /&gt;
* All export locations from available &amp;quot;active&amp;quot; replicas ''(Currently being pursued)''&lt;br /&gt;
* Export locations of active instances&lt;br /&gt;
* Export locations that are within the AZ of the active instance&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
10) Where do we store the &amp;quot;replication_change&amp;quot; status?&lt;br /&gt;
* On the instance &amp;quot;status&amp;quot; for the instance we are promoting ''(Currently being pursued)''&lt;br /&gt;
* On all the replica instances of the replicated share&lt;br /&gt;
* As a new status on the share itself&lt;br /&gt;
&lt;br /&gt;
11) 'replica_state' field should be 'healthy' or 'error' as current options 'in-sync' and 'out-of-sync'  may signify synchronous and async replication.&lt;br /&gt;
* Discussions with Ben in IRC&lt;br /&gt;
**  &amp;quot;the idea is that your redefine in-sync to mean &amp;quot;within the RPO guarantee of the async replication&amp;quot;&amp;quot;&lt;br /&gt;
** The user should know if it's async or sync replication by the 'description' in the share type.&lt;br /&gt;
** &amp;quot;the main thing that in-sync/out-of-sync is supposed to communicate is whether the replica is &amp;quot;good enough&amp;quot; that you could fail over to it&amp;quot;&lt;br /&gt;
12) 'replication' field on the share should qualify whether the replication is sync or async, so the options should be [&amp;quot;readable_sync&amp;quot;,  &amp;quot;readable_async&amp;quot;, &amp;quot;writable&amp;quot;, &amp;quot;dr_sync&amp;quot;, &amp;quot;dr_async&amp;quot;]&lt;br /&gt;
* Discussions with Ben in IRC&lt;br /&gt;
** The user should know if it's async or sync replication by the 'description' in the share type.&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/Replication_API_Design&amp;diff=90906</id>
		<title>Manila/Replication API Design</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/Replication_API_Design&amp;diff=90906"/>
				<updated>2015-09-23T16:57:59Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* New APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Design =&lt;br /&gt;
&lt;br /&gt;
== Intro ==&lt;br /&gt;
&lt;br /&gt;
The Manila DR API will be implemented as an extension to the Manila API (not part of core) initially, because we want to prove the concept without investing heavily in support in reference implementation (generic driver) or automated testing/CI.&lt;br /&gt;
&lt;br /&gt;
== Replication styles ==&lt;br /&gt;
&lt;br /&gt;
There are 3 styles of DR that we would like to support in the long run:&lt;br /&gt;
# writeable - Amazon EFS-style synchronously replicated shares where all replicas are writeable. Failover it not supported and not needed.&lt;br /&gt;
# readable - Mirror-style replication with a primary (writeable) copy and one or more secondary (read-only) copies which can become writeable after a failover.&lt;br /&gt;
# dr - Generalized replication with secondary copies that are inaccessible until after a failover.&lt;br /&gt;
&lt;br /&gt;
== Replica states ==&lt;br /&gt;
&lt;br /&gt;
Each replica has a state which has 3 possible values:&lt;br /&gt;
# active - All writeable replicas are active&lt;br /&gt;
# in_sync - Passive replica which is up to date with the active replica, and can be promoted to active&lt;br /&gt;
# out_of_sync - Passive replica which has gone out of date, or new replica that is not yet up to date&lt;br /&gt;
&lt;br /&gt;
== New APIs ==&lt;br /&gt;
&lt;br /&gt;
We will implement a Manila extension that includes several new APIs needed to support replicated shares.&lt;br /&gt;
&lt;br /&gt;
* List share replicas - Takes a share ID. Returns a table of replicas with details. Must be a replicated share. Details include AZ, replica state (active, in_sync, out_of_sync) and export locations.&lt;br /&gt;
** GET /shares/&amp;lt;share-id&amp;gt;/replicas&lt;br /&gt;
* Show share replica details&lt;br /&gt;
** GET /shares/&amp;lt;share-id&amp;gt;/replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
* Add share replica - Takes a share ID, and an AZ. The share must not already have a replica in the specified AZ. Returns replica UUID (actually share instance UUID).&lt;br /&gt;
** POST /shares/&amp;lt;share-id&amp;gt;/replicas&lt;br /&gt;
* Remove share replica - Takes a replica UUID. Deletes the replica, regardless of state. Must not be the only active replica.&lt;br /&gt;
** DELETE /shares/&amp;lt;share-id&amp;gt;/replicas/&amp;lt;replica-id&amp;gt;&lt;br /&gt;
* Set active replica - Takes a replica UUID. Make that replica active. The state of the replica must be in_sync.&lt;br /&gt;
** POST /shares/&amp;lt;share-id&amp;gt;/action&lt;br /&gt;
** {'os-promote_replica': {'replica_id': &amp;lt;replica-id&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
== New share states ==&lt;br /&gt;
&lt;br /&gt;
* replication_change - New transient state triggered by a change of the active replica. Access to the share is cut off while in this state.&lt;br /&gt;
&lt;br /&gt;
== Changes to existing APIs ==&lt;br /&gt;
&lt;br /&gt;
* Share type APIs will have a new user-visible extra spec - replication=writeable/readable/dr. The absence of this extra spec indicates non-replicated shares and the presence of the extra spec will indicate that the share is replicated with the given style.&lt;br /&gt;
* Share create will create a replicated share if the share type is has replication extra spec. The style of replication is determined by the share type's replication vale.&lt;br /&gt;
* Share list/details APIs will return the replication style (writeable, readable, dr) and a flag if more than one replica exists.&lt;br /&gt;
* Create snapshot - creates snapshots of all the replicas&lt;br /&gt;
* Delete share/snapshot - deletes ALL replicas of the share/snapshot&lt;br /&gt;
* Migrate/retype/etc - only the primary replica is considered as the source&lt;br /&gt;
&lt;br /&gt;
== Network issues with multi-SVM and replication ==&lt;br /&gt;
&lt;br /&gt;
!!OPTIONAL!!&lt;br /&gt;
&lt;br /&gt;
If we choose to make replication a single-svm-only feature, the share-network&lt;br /&gt;
API doesn't need to change. In order to support replication with share-networks, we also&lt;br /&gt;
need to modify the share-network create API which allows creation of share networks with&lt;br /&gt;
a table of AZ-to-subnet mappings. This approach allows us to keep a&lt;br /&gt;
single share-network per share (with associated security service) while allowing the&lt;br /&gt;
tenant to specify enough information that each share instance can be attached to the&lt;br /&gt;
appropriate network in each AZ. Multi-AZ share networks would also be useful for&lt;br /&gt;
non-replicated use cases.&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
&lt;br /&gt;
== Writable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication=writeable&lt;br /&gt;
# Administrator creates a new share_type called foo&lt;br /&gt;
# Administrator sets replication=writeable extra spec on share type foo&lt;br /&gt;
# User creates new share of type foo in AZ b1&lt;br /&gt;
# Share is created with replication=writeable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to active (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 writes some data to the share, which is immediately visible to client1&lt;br /&gt;
&lt;br /&gt;
== Readable replication example ==&lt;br /&gt;
&lt;br /&gt;
# Administrator sets up backends in AZs b1 and b2 that have capability replication=readable&lt;br /&gt;
# Administrator creates a new share_type called bar&lt;br /&gt;
# Administrator sets replication=readable extra spec on share type bar&lt;br /&gt;
# User creates new share of type bar in AZ b1&lt;br /&gt;
# Share is created with replication=readable, and 1 active replica in AZ b1&lt;br /&gt;
# User grants access on share to client1 in AZ b1, obtains the export location of the replica, mounts the share on a client, and starts to write data&lt;br /&gt;
# User add new replica of share in AZ b2&lt;br /&gt;
# A second replica is created in AZ b2 which initially has state out_of_sync&lt;br /&gt;
# Shortly afterwards, the replica state changes to in_sync (after the replica finishes syncing with the original copy)&lt;br /&gt;
# The user grants access on the share to client2 in AZ b2, obtains the export location of the new replica, mounts the share, and sees the same data that client1 wrote&lt;br /&gt;
# Client2 cannot write data to the share but continues to see updates&lt;br /&gt;
&lt;br /&gt;
== Failover/failback example ==&lt;br /&gt;
&lt;br /&gt;
(Continued from above)&lt;br /&gt;
# An outage occurs in AZ b1&lt;br /&gt;
# Administrator sends out a bulletin about the outage to his users &amp;quot;the power transformer in b1 turned to slag, it will be 12 hours before it can be replaced, please bear with us, yada yada&amp;quot;&lt;br /&gt;
# User notices that his application on client1 is no longer running, and investigates&lt;br /&gt;
# User finds out that client1 is gone, and reads a bulletin from the admin explaining why&lt;br /&gt;
# User notes that the b1 replica is his share is still active and the b2 replica is in_sync, while the state of the share is available&lt;br /&gt;
# User calls set active replica to AZ b2 on his share&lt;br /&gt;
# The share goes to state replication_change and access to the share is briefly lost on client2&lt;br /&gt;
# The state of replica b2 changes to active and the state of replica b1 changes to out_of_sync after Manila fails to contact the original primary. The state of the share changes back to available, and access is restored on client2&lt;br /&gt;
# User starts his application on client2, and the application recovers from an apparent crash, with a consistent copy of the application's data&lt;br /&gt;
# User application is back up and running, disaster is averted&lt;br /&gt;
# Eventually maintenance on the b1 AZ is completed, and all of the equipment is reactivated&lt;br /&gt;
# Administrator sends out a bulletin to his users about the outage ending &amp;quot;we replaced the transformer with a better one, everything is back online, thanks for your understanding, yada yada&amp;quot;&lt;br /&gt;
# Manila notices the out_of_sync replica is reachable and initiates a resync, bringing the b1 replica in_sync within a short time&lt;br /&gt;
# After some time, the users reads the bulletin and observes that his share is being replicated again. He decides to intentionally move back to b1.&lt;br /&gt;
# User gracefully shuts down his application, and flushes I/O&lt;br /&gt;
# User calls set active replica to AZ b1 on his share&lt;br /&gt;
# The share goes to state replication_change and no disruption is observed because the application is shut down&lt;br /&gt;
# The state of replica b1 changes to active and the state of replica b2 changes to in_sync after Manila reverses the replication again. The state of the share changes back to available&lt;br /&gt;
# User starts his application on client1, and the application starts cleanly, having been shut down gracefully&lt;br /&gt;
&lt;br /&gt;
= Notes =&lt;br /&gt;
&lt;br /&gt;
== Pool-level Replication ==&lt;br /&gt;
&lt;br /&gt;
Some vendors have suggested that certain backends can mirror groups of shares or whole pools more efficiently than individual shares. This design only addresses the mirroring of individual shares. In the future, we may allow allow replication of groups of shares, but only if those groups are contained within a single tenant and defined by the tenant.&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=88120</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=88120"/>
				<updated>2015-08-15T20:00:24Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Detailed CG */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 36,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_network_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share network to provision the CG and all of it's shares into&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 36,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_server_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share server on which the CG is provisioned, visible only to admins&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 36,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== CG Snapshot member ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot Member&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a member of a CGSnapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the parent cg_snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_type_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share_type of the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;size&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The storage size of this snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_protocol&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share protocol of the parent share&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 { &amp;quot;consistency_group&amp;quot; {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;:  detailed CG}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Simple CG]}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Detailed CG]}&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
{'cgsnapshot&amp;quot;:  {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }}&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  detailed CGSnapshot}&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  Detailed CGSnapshot}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=88119</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=88119"/>
				<updated>2015-08-15T19:59:04Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** The api will be an 'experimental' microversion in the Liberty release&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Create new shares from CG snapshot members in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# Call the driver with all info about source shares, new shares, cg, and cgsnapshot info.&lt;br /&gt;
*# Update CGsnapshot status and all shares status' to available&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
    share_network_id = Column(String(36), ForeignKey('share_networks.id'),&lt;br /&gt;
                              nullable=True)&lt;br /&gt;
    share_server_id = Column(String(36), ForeignKey('share_servers.id'),&lt;br /&gt;
                              nullable=True)&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
   consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.consistency_group_id '&lt;br /&gt;
                     '== ConsistencyGroup.id,'&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
 &lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshots&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'CGSnapshot.consistency_group_id == ConsistencyGroup.id,'&lt;br /&gt;
                     'CGSnapshot.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
 &lt;br /&gt;
    share = orm.relationship(Share, backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
                             foreign_keys=share_id,&lt;br /&gt;
                             primaryjoin='and_('&lt;br /&gt;
                             'CGSnapshotMember.share_id == Share.id,'&lt;br /&gt;
                             'CGSnapshotMember.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /consistency-groups/&lt;br /&gt;
 '''GET''' /consistency-groups/detail&lt;br /&gt;
 '''POST''' /consistency-groups&lt;br /&gt;
 '''GET''' /consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /cgsnapshots/&lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
 '''PUT''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 Body:&lt;br /&gt;
 {&amp;quot;os-reset_status&amp;quot;: { &amp;quot;status&amp;quot;: &amp;quot;available&amp;quot;}}&lt;br /&gt;
 '''POST''' /cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 Body:&lt;br /&gt;
 {&amp;quot;os-force_delete&amp;quot;: null}&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=88118</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=88118"/>
				<updated>2015-08-15T19:58:29Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: API extension -&amp;gt; experimental api&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** The api will be an 'experimental' microversion in the Liberty release&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Create new shares from CG snapshot members in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# Call the driver with all info about source shares, new shares, cg, and cgsnapshot info.&lt;br /&gt;
*# Update CGsnapshot status and all shares status' to available&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
    share_network_id = Column(String(36), ForeignKey('share_networks.id'),&lt;br /&gt;
                              nullable=True)&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
   consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.consistency_group_id '&lt;br /&gt;
                     '== ConsistencyGroup.id,'&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
 &lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshots&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'CGSnapshot.consistency_group_id == ConsistencyGroup.id,'&lt;br /&gt;
                     'CGSnapshot.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
 &lt;br /&gt;
    share = orm.relationship(Share, backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
                             foreign_keys=share_id,&lt;br /&gt;
                             primaryjoin='and_('&lt;br /&gt;
                             'CGSnapshotMember.share_id == Share.id,'&lt;br /&gt;
                             'CGSnapshotMember.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /consistency-groups/&lt;br /&gt;
 '''GET''' /consistency-groups/detail&lt;br /&gt;
 '''POST''' /consistency-groups&lt;br /&gt;
 '''GET''' /consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /cgsnapshots/&lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
 '''PUT''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 Body:&lt;br /&gt;
 {&amp;quot;os-reset_status&amp;quot;: { &amp;quot;status&amp;quot;: &amp;quot;available&amp;quot;}}&lt;br /&gt;
 '''POST''' /cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 Body:&lt;br /&gt;
 {&amp;quot;os-force_delete&amp;quot;: null}&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_FC_CI&amp;diff=88086</id>
		<title>ThirdPartySystems/NetApp FC CI</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_FC_CI&amp;diff=88086"/>
				<updated>2015-08-14T16:57:21Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ThirdPartySystemInfo|name=NetApp FC CI&lt;br /&gt;
|account=netapp-fc-ci&lt;br /&gt;
|contact= xdl-openstack-jenkins@netapp.com, andrew.kerr@netapp.com (akerr), alex.meade@netapp.com (ameade)&lt;br /&gt;
|intent=Test Openstack with NetApp Fibre Channel Cinder drivers using storage arrays&lt;br /&gt;
|structure=Nodepool, Zuul, Jenkins, modified upstream components with local configuration&lt;br /&gt;
|method=Using Zuul to connect to Gerrit&lt;br /&gt;
|programs=Cinder&lt;br /&gt;
|status= posting on openstack/cinder}}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=88036</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=88036"/>
				<updated>2015-08-13T19:06:52Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** /os-consistency-groups and /os-cgsnapshots are implemented as extensions and therefore entirely optional APIs&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /os-consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Create new shares from CG snapshot members in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# Call the driver with all info about source shares, new shares, cg, and cgsnapshot info.&lt;br /&gt;
*# Update CGsnapshot status and all shares status' to available&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
    share_network_id = Column(String(36), ForeignKey('share_networks.id'),&lt;br /&gt;
                              nullable=True)&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
   consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.consistency_group_id '&lt;br /&gt;
                     '== ConsistencyGroup.id,'&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
 &lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshots&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'CGSnapshot.consistency_group_id == ConsistencyGroup.id,'&lt;br /&gt;
                     'CGSnapshot.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
 &lt;br /&gt;
    share = orm.relationship(Share, backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
                             foreign_keys=share_id,&lt;br /&gt;
                             primaryjoin='and_('&lt;br /&gt;
                             'CGSnapshotMember.share_id == Share.id,'&lt;br /&gt;
                             'CGSnapshotMember.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 Body:&lt;br /&gt;
 {&amp;quot;os-reset_status&amp;quot;: { &amp;quot;status&amp;quot;: &amp;quot;available&amp;quot;}}&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 Body:&lt;br /&gt;
 {&amp;quot;os-force_delete&amp;quot;: null}&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87980</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87980"/>
				<updated>2015-08-13T14:22:14Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Driver API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** /os-consistency-groups and /os-cgsnapshots are implemented as extensions and therefore entirely optional APIs&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /os-consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Create new shares from CG snapshot members in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# Call the driver with all info about source shares, new shares, cg, and cgsnapshot info.&lt;br /&gt;
*# Update CGsnapshot status and all shares status' to available&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
    share_network_id = Column(String(36), ForeignKey('share_networks.id'),&lt;br /&gt;
                              nullable=True)&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
   consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.consistency_group_id '&lt;br /&gt;
                     '== ConsistencyGroup.id,'&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
 &lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshots&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'CGSnapshot.consistency_group_id == ConsistencyGroup.id,'&lt;br /&gt;
                     'CGSnapshot.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
 &lt;br /&gt;
    share = orm.relationship(Share, backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
                             foreign_keys=share_id,&lt;br /&gt;
                             primaryjoin='and_('&lt;br /&gt;
                             'CGSnapshotMember.share_id == Share.id,'&lt;br /&gt;
                             'CGSnapshotMember.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87970</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87970"/>
				<updated>2015-08-13T13:35:26Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* DB */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** /os-consistency-groups and /os-cgsnapshots are implemented as extensions and therefore entirely optional APIs&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /os-consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Create new shares from CG snapshot members in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# Call the driver with all info about source shares, new shares, cg, and cgsnapshot info.&lt;br /&gt;
*# Update CGsnapshot status and all shares status' to available&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
    share_network_id = Column(String(36), ForeignKey('share_networks.id'),&lt;br /&gt;
                              nullable=True)&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
   consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.consistency_group_id '&lt;br /&gt;
                     '== ConsistencyGroup.id,'&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
 &lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshots&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'CGSnapshot.consistency_group_id == ConsistencyGroup.id,'&lt;br /&gt;
                     'CGSnapshot.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
 &lt;br /&gt;
    share = orm.relationship(Share, backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
                             foreign_keys=share_id,&lt;br /&gt;
                             primaryjoin='and_('&lt;br /&gt;
                             'CGSnapshotMember.share_id == Share.id,'&lt;br /&gt;
                             'CGSnapshotMember.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87969</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87969"/>
				<updated>2015-08-13T13:34:56Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** /os-consistency-groups and /os-cgsnapshots are implemented as extensions and therefore entirely optional APIs&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /os-consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Create new shares from CG snapshot members in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# Call the driver with all info about source shares, new shares, cg, and cgsnapshot info.&lt;br /&gt;
*# Update CGsnapshot status and all shares status' to available&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
    share_network_id = Column(String(36), ForeignKey('share_networks.id'),&lt;br /&gt;
                              nullable=True)&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
   consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.consistency_group_id '&lt;br /&gt;
                     '== ConsistencyGroup.id,'&lt;br /&gt;
                     'ConsistencyGroupShareTypeMapping.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshots&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
                     'CGSnapshot.consistency_group_id == ConsistencyGroup.id,'&lt;br /&gt;
                     'CGSnapshot.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
    share = orm.relationship(Share, backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
                             foreign_keys=share_id,&lt;br /&gt;
                             primaryjoin='and_('&lt;br /&gt;
                             'CGSnapshotMember.share_id == Share.id,'&lt;br /&gt;
                             'CGSnapshotMember.deleted == &amp;quot;False&amp;quot;)')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87968</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87968"/>
				<updated>2015-08-13T13:31:20Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* System Workflows */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** /os-consistency-groups and /os-cgsnapshots are implemented as extensions and therefore entirely optional APIs&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /os-consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Create new shares from CG snapshot members in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# Call the driver with all info about source shares, new shares, cg, and cgsnapshot info.&lt;br /&gt;
*# Update CGsnapshot status and all shares status' to available&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87966</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87966"/>
				<updated>2015-08-13T13:28:11Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* User Workflows */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** /os-consistency-groups and /os-cgsnapshots are implemented as extensions and therefore entirely optional APIs&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /os-consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87965</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87965"/>
				<updated>2015-08-13T13:27:15Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Manila vs Cinder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** /os-consistency-groups and /os-cgsnapshots are implemented as extensions and therefore entirely optional APIs&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /os-consistency-groups&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is supported via the admin actions extension (/action)&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87964</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87964"/>
				<updated>2015-08-13T13:24:48Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is only supported via the admin actions extension /action&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
&lt;br /&gt;
 Updates to Share resource&lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Adds source_cgsnapshot_member_id&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87963</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87963"/>
				<updated>2015-08-13T13:23:00Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Resource schemas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 36,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_network_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share network to provision the CG and all of it's shares into&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 36,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== CG Snapshot member ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot Member&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a member of a CGSnapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the parent cg_snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_type_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share_type of the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;size&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The storage size of this snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_protocol&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share protocol of the parent share&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 { &amp;quot;consistency_group&amp;quot; {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;:  detailed CG}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Simple CG]}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Detailed CG]}&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
{'cgsnapshot&amp;quot;:  {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }}&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  detailed CGSnapshot}&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  Detailed CGSnapshot}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=87726</id>
		<title>Manila/Meetings</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/Meetings&amp;diff=87726"/>
				<updated>2015-08-11T14:05:31Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Next meeting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Weekly Manila team meeting =&lt;br /&gt;
'''NOTE MEETING TIME: Thursday at 15:00 UTC'''&lt;br /&gt;
&lt;br /&gt;
If you're interested in management of shared filesystems for OpenStack, we have a weekly meetings in &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#openstack-meeting-alt&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, on Thursdays at 15:00 UTC.  Please feel free to add items to the agenda below.  NOTE: When adding topics please include your IRC name so we know who's topic it is and how to get more info.&lt;br /&gt;
&lt;br /&gt;
== Next meeting ==&lt;br /&gt;
'''NOTE:''' ''Include your IRC nickname next to agenda items so that you can be called upon in the meeting and arrive at the meeting promptly if placing items in agenda. You might want to put this on your calendar if you are adding items.''&lt;br /&gt;
&lt;br /&gt;
'''Scheduled for 13 Aug, 2015, 15:00 UTC'''&lt;br /&gt;
# Consistency Groups discussion&lt;br /&gt;
#* Checkpoint on design and implementation&lt;br /&gt;
#* Experimental API vs extension&lt;br /&gt;
# Open Discussion&lt;br /&gt;
&lt;br /&gt;
== Previous meetings ==&lt;br /&gt;
&lt;br /&gt;
http://eavesdrop.openstack.org/meetings/manila/&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87694</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87694"/>
				<updated>2015-08-10T23:15:43Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Manila vs Cinder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, os-force_delete is only supported via the admin actions extension /action&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 &lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87693</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87693"/>
				<updated>2015-08-10T23:09:56Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Outstanding Questions / FAQ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, force_delete not supported until we have a standard API guideline&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 &lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; &lt;br /&gt;
#* Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87692</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87692"/>
				<updated>2015-08-10T23:08:18Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Outstanding Questions / FAQ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, force_delete not supported until we have a standard API guideline&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 &lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
#** (ameade) we have chosen to go with an os-consistency-groups extension for now&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* &amp;lt;strike&amp;gt; NO, but it will not be a core feature if it cannot be supported in the generic driver.&amp;lt;/strike&amp;gt; Ben says that we should fake it in the generic driver so it can be tested by the gate.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87691</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87691"/>
				<updated>2015-08-10T23:05:33Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, force_delete not supported until we have a standard API guideline&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Admin Actions&lt;br /&gt;
 '''POST''' /os-consistency-groups/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 '''POST''' /os-cgsnapshots/&amp;lt;id&amp;gt;/action # os-reset-status and os-force-delete&lt;br /&gt;
 &lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* NO, but it will not be a core feature if it cannot be supported in the generic driver.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87690</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87690"/>
				<updated>2015-08-10T23:03:36Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Driver API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, force_delete not supported until we have a standard API guideline&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
    def create_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_consistency_group_from_cgsnapshot(self, context, cg_dict,&lt;br /&gt;
                                                 cgsnapshot_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group from a cgsnapshot.&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict: The consistency group details&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'creating',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': 'False',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),&lt;br /&gt;
             'updated_at': None,&lt;br /&gt;
             'source_cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'host': 'openstack2@cmodeSSVMNFS',&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'shares': [&amp;lt;models.Share&amp;gt;], # The new shares being created&lt;br /&gt;
             'share_types': [&amp;lt;models.ConsistencyGroupShareTypeMapping&amp;gt;],&lt;br /&gt;
             'id': 'eda52174-0442-476d-9694-a58327466c14',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :param cgsnapshot_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            {'status': 'available',&lt;br /&gt;
             'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
             'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
             'description': None,&lt;br /&gt;
             'deleted': '0',&lt;br /&gt;
             'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
             'consistency_group_id': '4b04fdc3-00b9-4909-ba1a-06e9b3f88b67',&lt;br /&gt;
             'cgsnapshot_members': [&lt;br /&gt;
                {'status': 'available',&lt;br /&gt;
                 'share_type_id': '1a9ed31e-ee70-483d-93ba-89690e028d7f',&lt;br /&gt;
                 'share_id': 'e14b5174-e534-4f35-bc4f-fe81c1575d6f',&lt;br /&gt;
                 'user_id': 'a0314a441ca842019b0952224aa39192',&lt;br /&gt;
                 'deleted': 'False',&lt;br /&gt;
                 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share': &amp;lt;models.Share&amp;gt;,&lt;br /&gt;
                 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),&lt;br /&gt;
                 'share_proto': 'NFS',&lt;br /&gt;
                 'project_id': '13c0be6290934bd98596cfa004650049',&lt;br /&gt;
                 'cgsnapshot_id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
                 'deleted_at': None,&lt;br /&gt;
                 'id': '6813e06b-a8f5-4784-b17d-f3e91afa370e',&lt;br /&gt;
                 'size': 1&lt;br /&gt;
                }&lt;br /&gt;
             ],&lt;br /&gt;
             'deleted_at': None,&lt;br /&gt;
             'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',&lt;br /&gt;
             'name': None&lt;br /&gt;
            }&lt;br /&gt;
        :return: (cg_model_update, share_update_list)&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
  &lt;br /&gt;
            share_update_list - a list of dictionaries containing dicts for&lt;br /&gt;
            every share created in the CG. Any share dicts should at a minimum&lt;br /&gt;
            contain the 'id' key and 'export_locations'. Export locations&lt;br /&gt;
            should be in the same format as returned by a share_create. This&lt;br /&gt;
            list may be empty or None.&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
            [&lt;br /&gt;
             {'id': 'uuid', 'export_locations': ['export_path']}&lt;br /&gt;
            ]&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def delete_consistency_group(self, context, cg_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group&lt;br /&gt;
 &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param cg_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: cg_model_update&lt;br /&gt;
            cg_model_update - a dict containing any values to be updated&lt;br /&gt;
            for the CG in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
 &lt;br /&gt;
    def create_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Create a consistency group snapshot.&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
 &lt;br /&gt;
            member_update_list -  a list of dictionaries containing for every&lt;br /&gt;
            member of the cgsnapshot. Each dict should contains values to be&lt;br /&gt;
            updated for teh CGSnapshotMember in the database. This list may be&lt;br /&gt;
            empty or None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
    def delete_cgsnapshot(self, context, snap_dict, share_server=None):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Delete a consistency group snapshot&lt;br /&gt;
  &lt;br /&gt;
        :param context:&lt;br /&gt;
        :param snap_dict:&lt;br /&gt;
            EXAMPLE:&lt;br /&gt;
        :return: (cgsnapshot_update, member_update_list)&lt;br /&gt;
            cgsnapshot_update - a dict containing any values to be updated&lt;br /&gt;
            for the CGSnapshot in the database. This value may be None.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        raise NotImplementedError()&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* NO, but it will not be a core feature if it cannot be supported in the generic driver.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87556</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87556"/>
				<updated>2015-08-06T17:38:25Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* CG Snapshot member */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== CG Snapshot member ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot Member&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a member of a CGSnapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the parent cg_snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_type_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share_type of the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;size&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The storage size of this snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_protocol&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share protocol of the parent share&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 { &amp;quot;consistency_group&amp;quot; {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;:  detailed CG}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Simple CG]}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Detailed CG]}&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
{'cgsnapshot&amp;quot;:  {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }}&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  detailed CGSnapshot}&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  Detailed CGSnapshot}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87555</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87555"/>
				<updated>2015-08-06T17:36:32Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Resource schemas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== CG Snapshot member ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot Member&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a member of a CGSnapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
       &amp;quot;cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the parent cg_snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
     &amp;quot;share_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
     &amp;quot;share_type_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share_type of the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
     &amp;quot;size&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The storage size of this snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
     &amp;quot;share_protocol&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share protocol of the parent share&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 { &amp;quot;consistency_group&amp;quot; {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;:  detailed CG}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Simple CG]}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Detailed CG]}&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
{'cgsnapshot&amp;quot;:  {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }}&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  detailed CGSnapshot}&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  Detailed CGSnapshot}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87554</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87554"/>
				<updated>2015-08-06T17:07:24Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Request schemas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== CG Snapshot member ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot Member&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a member of a CGSnapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
       &amp;quot;cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the parent cg_snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
     &amp;quot;share_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 { &amp;quot;consistency_group&amp;quot; {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;:  detailed CG}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Simple CG]}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: &lt;br /&gt;
 {'consistency_groups&amp;quot;: [Detailed CG]}&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
{'cgsnapshot&amp;quot;:  {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }}&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  detailed CGSnapshot}&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  Detailed CGSnapshot}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87553</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87553"/>
				<updated>2015-08-06T17:06:24Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Request schemas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== CG Snapshot member ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot Member&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a member of a CGSnapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
       &amp;quot;cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the parent cg_snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
     &amp;quot;share_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
{ &amp;quot;consistency_group&amp;quot; {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 Response: &lt;br /&gt;
{'consistency_group&amp;quot;:  detailed CG}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: &lt;br /&gt;
{'consistency_groups&amp;quot;: [Simple CG]}&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: &lt;br /&gt;
{'consistency_groups&amp;quot;: [Detailed CG]}&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'consistency_group&amp;quot;: Detailed CG}&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
{'cgsnapshot&amp;quot;:  {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }}&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  detailed CGSnapshot}&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: {'cgsnapshot&amp;quot;:  Detailed CGSnapshot}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87552</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87552"/>
				<updated>2015-08-06T16:59:34Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Simple CG Snapshot */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== CG Snapshot member ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot Member&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a member of a CGSnapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
       &amp;quot;cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the parent cg_snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
     &amp;quot;share_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: Simple CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CGSnapshot&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CGSnapshot&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87550</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87550"/>
				<updated>2015-08-06T16:58:36Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Detailed CG Snapshot */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== CG Snapshot member ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot Member&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a member of a CGSnapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
       &amp;quot;cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the parent cg_snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
     &amp;quot;share_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for the share this snapshot was created from.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: Simple CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CGSnapshot&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CGSnapshot&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87546</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87546"/>
				<updated>2015-08-06T16:51:00Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* POST /os-cgsnapshots */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: Simple CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CGSnapshot&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CG&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87545</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87545"/>
				<updated>2015-08-06T16:50:36Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* POST /os-cgsnapshots */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: Simple CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: ['consistency_group_id']&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CG&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CG&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_FC_CI&amp;diff=87539</id>
		<title>ThirdPartySystems/NetApp FC CI</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=ThirdPartySystems/NetApp_FC_CI&amp;diff=87539"/>
				<updated>2015-08-06T15:44:09Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ThirdPartySystemInfo|name=NetApp FC CI&lt;br /&gt;
|account=netapp-fc-ci&lt;br /&gt;
|contact= xdl-openstack-jenkins@netapp.com, andrew.kerr@netapp.com (akerr), alex.meade@netapp.com (ameade)&lt;br /&gt;
|intent=Test Openstack with NetApp Fibre Channel Cinder drivers using storage arrays&lt;br /&gt;
|structure=Nodepool, Zuul, Jenkins, modified upstream components with local configuration&lt;br /&gt;
|method=Using Zuul to connect to Gerrit&lt;br /&gt;
|programs=Cinder&lt;br /&gt;
|status= On hold until https://bugs.launchpad.net/nova/+bug/1482092 is fixed}}&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87190</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87190"/>
				<updated>2015-08-01T19:25:14Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* User Workflows */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, force_delete not supported until we have a standard API guideline&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Create a CG&lt;br /&gt;
*# POST to /os-consistency-group&lt;br /&gt;
*#* specifiy share_types or the default share type will be used&lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
 def create_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
 def delete_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
 def create_cgsnapshot(self, context, cgsnapshot):&lt;br /&gt;
&lt;br /&gt;
 def delete_cgsnapshot(self, context, cgsnapshot):&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
 def update_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* NO, but it will not be a core feature if it cannot be supported in the generic driver.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87189</id>
		<title>Manila/design/manila-liberty-consistency-groups/api-schema</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups/api-schema&amp;diff=87189"/>
				<updated>2015-08-01T19:03:54Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Request schemas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Resource schemas=&lt;br /&gt;
&lt;br /&gt;
== Simple CG ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Detailed CG ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;host&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The backend where the CG lives&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;array&amp;quot;,&lt;br /&gt;
            &amp;quot;items&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Simple CG Snapshot ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CGsnapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Detailed CG Snapshot ==&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The unique identifier for a product&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,&lt;br /&gt;
            'pattern': ('^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}'&lt;br /&gt;
                        '-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$'),&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;created_at&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The time at which the CG snapshot was created&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;status&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;Status of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            &amp;quot;enum&amp;quot;: [&amp;quot;creating&amp;quot;, &amp;quot;available&amp;quot;, &amp;quot;deleting&amp;quot;, &amp;quot;error&amp;quot;]&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;project_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The owner of the CG snapshot&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the consistency group from which this CG snapshot was created.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: [&amp;quot;id&amp;quot;, &amp;quot;name&amp;quot;, &amp;quot;description&amp;quot;, &amp;quot;created_at&amp;quot;, &amp;quot;status&amp;quot;, &amp;quot;project_id&amp;quot;, &amp;quot;host&amp;quot;]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Request schemas =&lt;br /&gt;
&lt;br /&gt;
== POST /os-consistency-groups ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;source_cgsnapshot_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the cgsnapshot from which this CG was created. Cannot be supplied when 'share_types' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: ['null', 'string'],&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;share_types&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The share types that shares in the CG are allowed to be a part of. Cannot be supplied when 'source_cgsnapshot_id' is provided.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups ==&lt;br /&gt;
 Response: Simple CG&lt;br /&gt;
&lt;br /&gt;
== GET /os-consistency-groups/detail ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
==  GET /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-consistency-groups/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group (CG)&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a group of shares that can be snapshotted in unison&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CG&lt;br /&gt;
&lt;br /&gt;
== POST /os-cgsnapshots ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;consistency_group_id&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;The uuid of the CG from which to create this CG snapshot.&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: 'string',&lt;br /&gt;
        },&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: detailed CG&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== PUT /os-cgsnapshots/&amp;lt;id&amp;gt; ==&lt;br /&gt;
 {&lt;br /&gt;
    &amp;quot;$schema&amp;quot;: &amp;quot;http://json-schema.org/draft-04/schema#&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;: &amp;quot;Consistency Group Snapshot&amp;quot;,&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;A resource representing a snapshot of a group of shares&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,&lt;br /&gt;
    &amp;quot;properties&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A non-unique name for a CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,&lt;br /&gt;
            'maxLength': 255,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;description&amp;quot;: {&lt;br /&gt;
            &amp;quot;description&amp;quot;: &amp;quot;A short description of the CG&amp;quot;,&lt;br /&gt;
            &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
    &amp;quot;required&amp;quot;: []&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Response: Detailed CG&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87188</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87188"/>
				<updated>2015-08-01T17:10:03Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: update to os-consistency-groups&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, force_delete not supported until we have a standard API guideline&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /os-consistency-groups/&lt;br /&gt;
 '''GET''' /os-consistency-groups/detail&lt;br /&gt;
 '''POST''' /os-consistency-groups&lt;br /&gt;
 '''GET''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /os-consistency-groups/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /os-cgsnapshots/&lt;br /&gt;
 '''GET''' /os-cgsnapshots/detail&lt;br /&gt;
 '''POST''' /os-cgsnapshots&lt;br /&gt;
 '''PUT''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /os-cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /os-cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
 def create_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
 def delete_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
 def create_cgsnapshot(self, context, cgsnapshot):&lt;br /&gt;
&lt;br /&gt;
 def delete_cgsnapshot(self, context, cgsnapshot):&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
 def update_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* NO, but it will not be a core feature if it cannot be supported in the generic driver.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	<entry>
		<id>https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87168</id>
		<title>Manila/design/manila-liberty-consistency-groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.openstack.org/w/index.php?title=Manila/design/manila-liberty-consistency-groups&amp;diff=87168"/>
				<updated>2015-07-31T18:30:40Z</updated>
		
		<summary type="html">&lt;p&gt;Alex Meade: /* Cinder Bugs to file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Consistency Groups =&lt;br /&gt;
This document describes the design choices and steps for the consistency group feature in core Manila.&lt;br /&gt;
&lt;br /&gt;
Consistency groups are a mechanism to allow multiple filesystem shares to be guaranteed snapshots are able to be created at the exact same point in time. For example, a database may have its tables, logs, and configuration on separate volumes. If we wanted to restore the database from a previous point in time, it would only make sense to restore the logs, tables, and configuration together from the exact same point in time.&lt;br /&gt;
&lt;br /&gt;
= Manila Core Changes =&lt;br /&gt;
The core manila changes are very similar to what has been done in Cinder. At a high level, changes in the DB, share service, drivers, scheduler service and api service will need to be changed.&lt;br /&gt;
&lt;br /&gt;
Phase 1:&lt;br /&gt;
* Create/Delete CGs&lt;br /&gt;
* Create a share within a CG&lt;br /&gt;
* Delete a share that is in a CG&lt;br /&gt;
* Snapshot entire CGs&lt;br /&gt;
* Create CG from a CGSnapshot&lt;br /&gt;
&lt;br /&gt;
Potential future features:&lt;br /&gt;
* Add/remove shares in a CG&lt;br /&gt;
* CG migration&lt;br /&gt;
* Replication of a CG&lt;br /&gt;
&lt;br /&gt;
==Manila vs Cinder==&lt;br /&gt;
* Different CLI syntax&lt;br /&gt;
* Restful api tweaks&lt;br /&gt;
** Change /create_from_src to just be a cgsnapshot_id in the body on POST /shares&lt;br /&gt;
** Deletes to use the DELETE HTTP verb, force_delete not supported until we have a standard API guideline&lt;br /&gt;
* At the Driver API, cgsnapshot objects and cg objects (with all the information about what volumes are in the CG) need to be passed to the driver instead of just the cg/cgsnapshot name. This is important for backends that aren't managing a CG construct such as NetApp cDOT as they need to do things such as loop through the snapshots in a cg to delete them.&lt;br /&gt;
* The default policy in policy.json for consistency group operations is the default policy versus in Cinder is it 'nobody'&lt;br /&gt;
* Unlike Cinder, snapshots in a CGsnapshot are not the same as a normal snapshot. A CGsnapshot is treated as a single unit instead of a collection of snapshots.&lt;br /&gt;
* consistency_group_support scheduler capability has multiple values instead of boolean. This is to accommodate backends that require all volumes in a CG to be on the same pool vs. just the same host. It also allows for adding additional values in the future if a backend can support some other paradigm like a CG spanning multiple backends.&lt;br /&gt;
&lt;br /&gt;
== User Workflows ==&lt;br /&gt;
* Snapshot multiple shares&lt;br /&gt;
*# Create a Consistency Group&lt;br /&gt;
*# Create share(s) with a CG specified&lt;br /&gt;
*# Create a CGsnapshot &lt;br /&gt;
&lt;br /&gt;
* Copy a consistency group&lt;br /&gt;
*# Create a CGsnapshot&lt;br /&gt;
*# Create a CG with the CGSnapshot id&lt;br /&gt;
&lt;br /&gt;
* Delete a CG (and all of its shares)&lt;br /&gt;
*# Delete all CG snapshots of the CG&lt;br /&gt;
*# Delete all shares in the CG&lt;br /&gt;
*# Delete the CG (Only empty CGs can be deleted)&lt;br /&gt;
&lt;br /&gt;
* List shares in a given CG&lt;br /&gt;
*# GET /shares?consistencygroup_id=&amp;lt;cg_id&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* List the shares that were captured in a given CGSnapshot&lt;br /&gt;
*# GET /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
&lt;br /&gt;
== System Workflows ==&lt;br /&gt;
* Creating a CG&lt;br /&gt;
*# Create the CG in the DB&lt;br /&gt;
*# Cast the consistency group creation to the scheduler&lt;br /&gt;
*## Choose a host for the CG&lt;br /&gt;
*# Cast the creation to the share service&lt;br /&gt;
*## Get the CG info from DB&lt;br /&gt;
*## Call the driver&lt;br /&gt;
*## Update database with info returned from driver (ex: CG status)&lt;br /&gt;
&lt;br /&gt;
* Creating a CG from a cgsnapshot&lt;br /&gt;
*# Create a new CG in the DB&lt;br /&gt;
*# Schedule the CG create to the scheduler with the orig CG host/pool+share_type (depending on capability)&lt;br /&gt;
*# For each member of the snapshot, schedule a create share on the same host/pool as CG&lt;br /&gt;
&lt;br /&gt;
* Creating a cg snapshot&lt;br /&gt;
*# Create cgsnapshot entity in DB&lt;br /&gt;
*# For all shares in CG, create cgsnapshot_member in DB&lt;br /&gt;
*# cast create_cgsnapshot to the driver&lt;br /&gt;
&lt;br /&gt;
* Adding a share to a CG&lt;br /&gt;
** On share creation:&lt;br /&gt;
**# Cast to scheduler with the host of the CG &lt;br /&gt;
**#* if perpool capable: Goes to the same pool as CG&lt;br /&gt;
**#* if per backend: goes to a pool on the same host that matches a CG share type&lt;br /&gt;
&lt;br /&gt;
* Deleting a share (in a CG)&lt;br /&gt;
** Not allowed if the CG has snapshots of the share ( check if the share_id is in the CGSnapshotMembers tables)&lt;br /&gt;
&lt;br /&gt;
== Scheduler ==&lt;br /&gt;
manila/scheduler/filter_scheduler.py should now look for consistency_group_support as a capability.&lt;br /&gt;
&lt;br /&gt;
consistency_group_support&lt;br /&gt;
default: None&amp;lt;br /&amp;gt;&lt;br /&gt;
Values:&lt;br /&gt;
* None - No support for CGs&lt;br /&gt;
* host - shares in a CG must be on pool(s) on the same host that also match the CG share type&lt;br /&gt;
* pool - shares in a CG must live in the same pool as the CG&lt;br /&gt;
&lt;br /&gt;
==DB==&lt;br /&gt;
* New Tables:&lt;br /&gt;
 class ConsistencyGroup(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a consistencygroup.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_groups'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
  &lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    host = Column(String(255))&lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    source_cgsnapshot_id = Column(String(36))&lt;br /&gt;
 &lt;br /&gt;
 class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents the share types in a consistency group&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'consistency_group_share_type_mappings'&lt;br /&gt;
    id = Column(Integer, primary_key=True)&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
    consistency_group_id = Column(String(36), &lt;br /&gt;
                                  ForeignKey('consistency_groups.id'), &lt;br /&gt;
                                  nullable=False)&lt;br /&gt;
    share_type_id = Column(String(36), &lt;br /&gt;
                           ForeignKey('share_types.id'), &lt;br /&gt;
                           nullable=False)&lt;br /&gt;
    consistency_group = orm.relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;share_types&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin=('and_('&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.consistency_group_id == '&lt;br /&gt;
            'ConsistencyGroups.id,'&lt;br /&gt;
            'ConsistencyGroupShareTypeMapping.deleted == 0)')&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshot(BASE, ManilaBase):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Represents a cgsnapshot.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    __tablename__ = 'cgsnapshots'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
 &lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'))&lt;br /&gt;
    user_id = Column(String(255), nullable=False)&lt;br /&gt;
    project_id = Column(String(255), nullable=False)&lt;br /&gt;
 &lt;br /&gt;
    name = Column(String(255))&lt;br /&gt;
    description = Column(String(255))&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
&lt;br /&gt;
 class CGSnapshotMembers(BASE, ManilaBase):&lt;br /&gt;
    __tablename__ = 'cgsnapshot_members'&lt;br /&gt;
    id = Column(String(36), primary_key=True)&lt;br /&gt;
    cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))&lt;br /&gt;
    share_id = Column(String(36), ForeignKey('shares.id'))&lt;br /&gt;
    size = Column(Integer)&lt;br /&gt;
    status = Column(String(255))&lt;br /&gt;
    share_proto = Column(String(255))&lt;br /&gt;
    share_type_id = Column(String(36), ForeignKey('share_types.id'),&lt;br /&gt;
                           nullable=True)&lt;br /&gt;
    user_id = Column(String(255))&lt;br /&gt;
    project_id = Column(String(255))&lt;br /&gt;
    deleted = Column(String(36), default='False')&lt;br /&gt;
 &lt;br /&gt;
    cgsnapshot = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;cgsnapshot_members&amp;quot;,&lt;br /&gt;
        foreign_keys=cgsnapshot_id,&lt;br /&gt;
        primaryjoin='CGSnapshotMembers.cgsnapshot_id == CGSnapshot.id')&lt;br /&gt;
&lt;br /&gt;
* New fields in Share&lt;br /&gt;
    consistency_group_id = Column(String(36), ForeignKey('consistency_groups.id'), nullable=True)&lt;br /&gt;
    consistency_group = relationship(&lt;br /&gt;
        ConsistencyGroup,&lt;br /&gt;
        backref=&amp;quot;shares&amp;quot;,&lt;br /&gt;
        foreign_keys=consistency_group_id,&lt;br /&gt;
        primaryjoin='Share.consistency_group_id == ConsistencyGroup.id')&lt;br /&gt;
   &lt;br /&gt;
    source_cgsnapshot_member_id = Column(String(36), nullable=True)&lt;br /&gt;
&lt;br /&gt;
==API==&lt;br /&gt;
Schemas: https://wiki.openstack.org/wiki/Manila/design/manila-liberty-consistency-groups/api-schema&lt;br /&gt;
&lt;br /&gt;
 '''GET''' /consistencygroups/&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''DELETE''' consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/&lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
 '''PUT''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;/members&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistency_group_id to POST/shares&lt;br /&gt;
 Add consistency_group_id query filter to /shares&lt;br /&gt;
&lt;br /&gt;
==Policies==&lt;br /&gt;
policy.json - All consistency group policies should default to the default policy&lt;br /&gt;
    &amp;quot;consistency_group:create&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:update&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;consistency_group:create_cgsnapshot&amp;quot; : &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:delete_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_cgsnapshot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
    &amp;quot;consistency_group:get_all_cgsnapshots&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
==Driver API==&lt;br /&gt;
&lt;br /&gt;
update_share_stats should now return 'consistency_group_support' pool/host/None.&lt;br /&gt;
&lt;br /&gt;
 def create_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
 def delete_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
 def create_cgsnapshot(self, context, cgsnapshot):&lt;br /&gt;
&lt;br /&gt;
 def delete_cgsnapshot(self, context, cgsnapshot):&lt;br /&gt;
&lt;br /&gt;
Phase 2:&lt;br /&gt;
&lt;br /&gt;
 def update_consistency_group(self, context, cg):&lt;br /&gt;
&lt;br /&gt;
== Manila Client ==&lt;br /&gt;
* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;Do we want to alias the commands so that there are Cinder consistent commands and the improved names?&amp;lt;/font&amp;gt; (I.E cg-create = consisgroup-create) Perhaps we alias the cinderclient commands to be more like this?&lt;br /&gt;
   cg-snapshot-create   Creates a cgsnapshot.&lt;br /&gt;
   cg-snapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
   cg-snapshot-list     Lists all cgsnapshots.&lt;br /&gt;
   cg-snapshot-show     Shows cgsnapshot details.&lt;br /&gt;
  &lt;br /&gt;
   cg-create  Creates a consistency group (--cgsnapshot to create from existing cg snapshot)&lt;br /&gt;
   cg-delete  Removes one or more consistency groups.&lt;br /&gt;
   cg-list    Lists all consistencygroups.&lt;br /&gt;
   cg-show    Shows details of a consistency group.&lt;br /&gt;
   cg-update  Updates a consistencygroup.&lt;br /&gt;
&lt;br /&gt;
   create --consistency-group Creates a share and puts it into consistency group&lt;br /&gt;
&lt;br /&gt;
= Outstanding Questions / FAQ =&lt;br /&gt;
# How do we avoid confusion if no backends in a deployment support CGs?&lt;br /&gt;
#* It appears that Cinder has the policies default to 'nobody' but this seems odd, is there a better way?&lt;br /&gt;
#** (ameade) I can't think of a way to have devstack set the policies automatically either.&lt;br /&gt;
# Do we need a way to fake CGs with the generic driver?&lt;br /&gt;
#* NO, but it will not be a core feature if it cannot be supported in the generic driver.&lt;br /&gt;
# Do we need a safeguard for deleting shares that are in a CG? (I.E. protected shares?) Are shares in a CG more valuable than normal shares?&lt;br /&gt;
# Should we overload the Snapshots table to include snapshots in a CGSnapshot to avoid adding a new db table? Or continue with having a new table?&lt;br /&gt;
# Why not have the cg delete all of the shares in it when deleting the cg?&lt;br /&gt;
#* This could cause odd state to occur if the backend fails when deleting shares and it will not be obvious where it failed. This is also extra complexity in the implementation that could instead be hidden by a client.&lt;br /&gt;
&lt;br /&gt;
= Notes on Cinder Impl =&lt;br /&gt;
&lt;br /&gt;
* A consistency group may be specified on volume create&lt;br /&gt;
* When a consistency group is created it is scheduled to a pool and all volume created in the CG will go to that pol&lt;br /&gt;
&lt;br /&gt;
Cinder cli:&lt;br /&gt;
    cgsnapshot-create   Creates a cgsnapshot and snapshots of every volume in the CG that show up in snapshot-list.&lt;br /&gt;
    cgsnapshot-delete   Removes one or more cgsnapshots.&lt;br /&gt;
    cgsnapshot-list     Lists all cgsnapshots.&lt;br /&gt;
    cgsnapshot-show     Shows cgsnapshot details.  &amp;lt;-- /cgsnapshots/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-create  Creates a consistency group.&lt;br /&gt;
    consisgroup-create-from-src Creates a consistency group from a cgsnapshot filled with volumes from the snapshots in the cg.&lt;br /&gt;
    consisgroup-delete  Removes one or more consistency groups.&lt;br /&gt;
    consisgroup-list    Lists all consistencygroups.&lt;br /&gt;
    consisgroup-show    Shows details of a consistency group. &amp;lt;-- /consistencygroups/detail?all_tenants=1&amp;amp;name=blah&lt;br /&gt;
    consisgroup-update  Updates a consistencygroup.&lt;br /&gt;
    &lt;br /&gt;
    create --consisgroup-id&lt;br /&gt;
&lt;br /&gt;
Cinder API:&lt;br /&gt;
 '''GET''' /consistencygroups/detail&lt;br /&gt;
 '''POST''' /consistencygroups&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'volume_types': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'availability_zone': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''POST''' /consistencygroups/create_from_src&lt;br /&gt;
  {'consistencygroup-from-src':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'cgsnapshot_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''GET''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' consistencygroups/&amp;lt;id&amp;gt;/delete&lt;br /&gt;
   {&amp;quot;consistencygroup&amp;quot;: {&amp;quot;force&amp;quot;: false}}&lt;br /&gt;
 '''PUT''' /consistencygroups/&amp;lt;id&amp;gt;&lt;br /&gt;
  {'consistencygroup':{&lt;br /&gt;
    'name': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'description': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'add_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
    'remove_volumes': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 &lt;br /&gt;
 '''GET''' /cgsnapshots/detail&lt;br /&gt;
 '''GET''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 '''POST''' /cgsnapshots&lt;br /&gt;
  {'cgsnapshot':{&lt;br /&gt;
    'consistencygroup_id': &amp;lt;string&amp;gt;,&lt;br /&gt;
  }}&lt;br /&gt;
 '''DELETE''' /cgsnapshots/&amp;lt;id&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Adds consistencygroup_id to POST/volumes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xings commit message:&lt;br /&gt;
    1) Create a CG, specifying all volume types that can be supported by this&lt;br /&gt;
    CG. The scheduler chooses a backend that supports all specified volume types.&lt;br /&gt;
    The CG will be empty when it is first created.   Backend needs to report&lt;br /&gt;
    consistencygroup_support = True.  Volume type can have the following in&lt;br /&gt;
    extra specs: {'capabilities:consistencygroup_support': '&amp;lt;is&amp;gt; True'}.&lt;br /&gt;
    If consistencygroup_support is not in volume type extra specs, it will be&lt;br /&gt;
    added to filter_properties by the scheduler to make sure that the scheduler&lt;br /&gt;
    will select the backend which reports consistency group support capability.&lt;br /&gt;
    &lt;br /&gt;
    Create CG CLI:&lt;br /&gt;
    cinder consisgroup-create --volume-type type1,type2 mycg1&lt;br /&gt;
    &lt;br /&gt;
    This will add a CG entry in the new consistencygroups table.&lt;br /&gt;
    &lt;br /&gt;
    2) After the CG is created, create a new volume and add to the CG.&lt;br /&gt;
    Repeat until all volumes are created for the CG.&lt;br /&gt;
    &lt;br /&gt;
    Create volume CLI (with CG):&lt;br /&gt;
    cinder create --volume-type type1 --consisgroup-id &amp;lt;CG uuid&amp;gt; 10&lt;br /&gt;
    &lt;br /&gt;
    This will add a consistencygroup_id foreign key in the new volume&lt;br /&gt;
    entry in the db.&lt;br /&gt;
    &lt;br /&gt;
    3) Create a snapshot of the CG (cgsnapshot).&lt;br /&gt;
    &lt;br /&gt;
    Create cgsnapshot CLI:&lt;br /&gt;
    cinder cgsnapshot-create &amp;lt;CG uuid&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    This will add a cgsnapshot entry in the new cgsnapshots table, create&lt;br /&gt;
    snapshot for each volume in the CG, and add a cgsnapshot_id foreign key&lt;br /&gt;
    in each newly created snapshot entry in the db.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
# Why does policy.json default to 'nobody' being able to perform CG commands?&lt;br /&gt;
# Why are volume types specified when creating a CG?&lt;br /&gt;
#* This is because all volumes within a CG need to be on the same backend in order for the backend to honor the CG. This is important to note in the docs so that conflicting volume-types are not specified.&lt;br /&gt;
# What occurs when a volume on a different backend is added to a CG via the API?&lt;br /&gt;
#* Currently the API ensures that the volume volume_type matches a supported volume_type of the CG and that the CG and volume are on the same host (but can be on different pools).&lt;br /&gt;
# Is a volume created with a CG going to end up on the same host?&lt;br /&gt;
#* Yes, if a volume has a CG it will be cast to the same pool as the CG.&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;What if the pool is full but there are other available pools on the same backend? Should this fail?&amp;lt;/font&amp;gt;&lt;br /&gt;
# What happens if a driver does not support create_from_src?&lt;br /&gt;
#* The CG goes to ERROR a and volumes are created from the snapshot and also in ERROR status&lt;br /&gt;
#* A volume in a consistency group cannot be deleted and a CG with a volume cannot be deleted, therefore a volume must be removed from the CG before it can be deleted. &amp;lt;font color=&amp;quot;purple&amp;quot;&amp;gt;But what if you don't support modifying a CG?&amp;lt;/font&amp;gt;&lt;br /&gt;
# Why do we need a force delete for CGs?&lt;br /&gt;
# What do I do if I do not want to see Snapshots in a CG when doing snapshot-list?&lt;br /&gt;
#* I suppose API filtering could allow for someone to not see all of the snapshots if they do not want to.&lt;br /&gt;
&lt;br /&gt;
=== Cinder Bugs to file===&lt;br /&gt;
# What happens when you force delete a CG?&lt;br /&gt;
#* &amp;lt;font color=&amp;quot;red&amp;gt;The volumes remain but still think they are in a CG, which means you still cannot delete the volume&amp;lt;/font&amp;gt;&lt;br /&gt;
# consisgroup-create-from-src says cgsnapshot is and optional param in cinderclient&lt;br /&gt;
# Creating a volume in a CG may not end up in the cg. The only check that is performed is that the volume-type of the volume is supported by the CG but volume-types are not 1-to-1 with backends. There could be backend A and B that both match with volume type 1. A cg is created with volume type 1 and ends up on backend A. Then a volume is created with the CG specified but ends up on backend B&lt;br /&gt;
&lt;br /&gt;
=== Main impl ===&lt;br /&gt;
 299b99437c2de84222fd585f06c2d05ca213225b ConsistencyGroup: Return 400 instead of 500 for invalid body&lt;br /&gt;
 adb4c80be82caacad83f1366a4b34e5653fd5dab Create Consistency Group from CG Snapshot API&lt;br /&gt;
 1a62a6e60fda73bf31256fbf684dc03bb6cf0038 Modify Consistency Group API&lt;br /&gt;
 fc7a4384be2ccf8ff24f6c0f72c681ad9133801a Add tests for consistency groups DB migration &lt;br /&gt;
 9082273305b0b9c117eb677a0e34c2ffde4e66f0 Volume types need to be specified when creating CG&lt;br /&gt;
 764c5ec749821d36bb0215dc6002d3caea95d3b1 Delete consistency group failed&lt;br /&gt;
 cf961f83ac323dfad1fa5e227d1e502a17529ecc Consistency Groups&lt;br /&gt;
&lt;br /&gt;
=== Ex driver impl ===&lt;br /&gt;
 8d5b795b37ed021c2639066689645f8aa0b1012f PureISCSIDriver consistency group updates.&lt;br /&gt;
 39c1a8e08dc854e22ada315a46c20c99df2facf8 Add support to PureISCSIDriver for Consistency Groups&lt;br /&gt;
 92a817708a3938b1b734d2caaa206b310996d8d0 EMC VMAX driver Kilo update&lt;/div&gt;</summary>
		<author><name>Alex Meade</name></author>	</entry>

	</feed>