February 21, 2017


Endurance Storage Replication

Examples on ordering, snapshots, and replication for endurance storage.

Some good starting reading.

For more information on the magic of storage ordering see the following

This example should touch on all the basics of dealing with endurance storage replication volumes. This example uses the SoftLayer-python File manager a little bit for ordering

TO authorize hosts that are NOT virtual guests, see the allowAccessFrom* methods in

Graceful vs Immediate failover

Failback is always immediate.

"""
@package examples 
@author Christopher Gallo
"""

import SoftLayer
import logging
from pprint import pprint as pp

class example():

    def __init__(self):
        """
        If you need debugging, uncomment these. be prepared for a lot of XML
        """
        # logger = logging.getLogger()
        # logger.addHandler(logging.StreamHandler())
        # logger.setLevel(3)
        self.client = SoftLayer.Client()
        self.storage = self.client['SoftLayer_Network_Storage']
        self.mgr = SoftLayer.FileStorageManager(self.client)
        # Broken up like this to look 'good' on softlayer.github.io
        self.objectMask = "mask["
            "id, username, capacityGb, bytesUsed, serviceResource[datacenter[name]], "
            "serviceResourceBackendIpAddress, activeTransactionCount, "
            "fileNetworkMountAddress, snapshots[id,createDate], hourlySchedule, " 
            "allowedReplicationVirtualGuests[hostname], allowedVirtualGuests[hostname], "
            "replicationStatus, replicationPartners]"

    def orderStorage(self):
        """
        This will order endurance storage in HOU02 with 20G in size, and the 0.25IOPS/GB tier
        0.25, 2, 4 and 10 iops/g are tiers available. 
        """
        result = self.mgr.order_file_volume(
            storage_type="storage_service_enterprise",
            location = "hou02",
            size = 20,
            tier_level = 0.25
            )
        pp(result)

    def orderSnapshot(self, volume_id):
        result = self.mgr.order_snapshot_space(
            volume_id=volume_id,
            capacity=20,
            tier = 0.25,
            upgrade=False)
        pp(result)

    def orderReplicant(self, volume_id, schedule):
        """
        Same as other ordering methods, schedule is 
        "HOURLY", "DAILY" or "WEEKLY"
        """
        result = self.mgr.order_replicant_volume(
            volume_id=volume_id,
            snapshot_schedule=schedule,
            location = "dal06",
            tier = 0.25
        )
        pp(result)



    def listStoragePrices(self):
        """
        222 - Performance - PERFORMANCE_STORAGE_SERVICE
        240 - Endurance - CODENAME_PRIME_STORAGE
        If you feel like building the pricing object yourself, start here.
        """
        mask = "mask[items[prices[pricingLocationGroup,categories],attributes]]"
        # locations = self.client['Product_Package'].getLocations(id=package_id)
        result = self.client['Product_Package'].getObject(mask=mask,id=240)
        for item in result['items']:
            print("%s - %s - %s" % 
                (str(item['id']), item['description'], item['keyName']) 
            # pp(item)
            for prices in item['prices']:
                if prices['locationGroupId'] is  '':
                    print "\t" + str(prices['id'])
                # pp(prices)

    def listStorage(self):
    """
    Super complicated objectFilter. Mostly here as an example of how to do an IN filter.
    Returns all storage that is in DAL06, HOU02, is NOT NAS, and is Endurance_File_Storage
    """
        objectFilter = {
            'nasNetworkStorage': {
                'serviceResource': {
                    'type': {
                        'type': {'operation': '!~ NAS'}
                    },
                    'datacenter': {
                        'name': {
                            'operation': 'in',
                            'options': [{
                                'name': 'data',
                                'value': ['dal06','hou02']
                            }]
                        }
                    }
                },
                'storageType': {
                    'keyName': {'operation': 'ENDURANCE_FILE_STORAGE'}
                }
            }
        }
        result = self.client['Account'].getNasNetworkStorage(
            mask=self.objectMask,filter=objectFilter)
        pp(result)

    def authHost(self, volume_id, host_id):
    """
    each host that needs to mount the volume needs to be authorized.
    host and volume need to be in the same DC
    """
        guest = {
            'id': host_id
        }
        self.storage.allowAccessFromVirtualGuest(guest, id=volume_id)

    def authReplicant(self, volume_id, host_id):
    """
    each host that needs to mount the REPLICANT needs to be authorized.
    host and volume need to be in the same DC
    """
        guest = {
            'id': host_id
        }
        self.storage.allowAccessToReplicantFromVirtualGuest(guest, id=volume_id)

    def createSnapSchedule(self, volume_id):
        # HOURLY, 24 copies, first minute of the hour. 
        self.storage.enableSnapshots('HOURLY', 24, 1, 0, 0, id=volume_id)

    def manualSnap(self, volume_id):
        self.storage.createSnapshot('Manual SNAP', id=volume_id)

    def getReplicantId(self, volume_id):
        """
        there might be more than 1 replicant id in this list if there are more 
        than 1 replicant targets. Or none of course.
        """
        result = self.storage.getReplicationPartners(id=volume_id)
        return result[0]['id']
        

    def houIsDown(self, volume_id, now=False):

        replicate_to = main.getReplicantId(volume_id)
        if now:
            self.storage.immediateFailoverToReplicant(replicate_to, id=volume_id)
        else
            self.storage.failoverToReplicant(replicate_to, id=volume_id)

    def houIsBack(self, volume_id):
        self.storage.failbackFromReplicant(id=volume_id,now=False)

    def volumeStatus(self, volume_id):
        result = self.storage.getObject(mask=self.objectMask, id=volume_id)
        pp(result)


if __name__ == "__main__":
"""
Covers each of the steps required to create a storage volume, and then fail it over.
The ordering methods will need to be slightly modified for block storage. 
everything else should be good as is.

"""

    host_a = 25206857
    host_b = 28630647
    main = example()
    main.listStorage()
    ### First we need to order a storage volume, and get its ID.
    # main.orderStorage()
    volume_id = 20017773

    ### Then we need to order snapshot space
    # main.orderSnapshot(volume_id)

    ### Then create a snapshot schedule.
    # main.createSnapSchedule(volume_id)

    ### Then Allow our host to access the volume
    # main.authHost(volume_id, [host_a])

    ### Create a manual snapshot for fun 
    # main.manualSnap(volume_id)

    ### Order replication space.
    # main.orderReplicant(volume_id, 'HOURLY')

    ### Allow our vm to access replicant volume
    # main.authReplicant(volume_id,host_b)

    ### Failover to replicant
    # main.houIsDown(volume_id)

    ### Failback to main
    # main.houIsBack(volume_id)

    ### Get some status
    # main.volumeStatus(volume_id)