Source code for SoftLayer.managers.vs_capacity

"""
    SoftLayer.vs_capacity
    ~~~~~~~~~~~~~~~~~~~~~~~
    Reserved Capacity Manager and helpers

    :license: MIT, see License for more details.
"""

import logging

from SoftLayer.exceptions import SoftLayerError
from SoftLayer.managers import ordering
from SoftLayer.managers.vs import VSManager
from SoftLayer import utils

# Invalid names are ignored due to long method names and short argument names
# pylint: disable=invalid-name

LOGGER = logging.getLogger(__name__)


[docs] class CapacityManager(utils.IdentifierMixin, object): """Manages SoftLayer Reserved Capacity Groups. Product Information - https://cloud.ibm.com/docs/virtual-servers?topic=virtual-servers-about-reserved-virtual-servers - https://softlayer.github.io/reference/services/SoftLayer_Virtual_ReservedCapacityGroup/ - https://softlayer.github.io/reference/services/SoftLayer_Virtual_ReservedCapacityGroup_Instance/ :param SoftLayer.API.BaseClient client: the client instance :param SoftLayer.managers.OrderingManager ordering_manager: an optional manager to handle ordering. If none is provided, one will be auto initialized. """
[docs] def __init__(self, client, ordering_manager=None): self.client = client self.account = client['Account'] self.capacity_package = 'RESERVED_CAPACITY' self.rcg_service = 'Virtual_ReservedCapacityGroup' if ordering_manager is None: self.ordering_manager = ordering.OrderingManager(client)
[docs] def list(self): """List Reserved Capacities""" mask = """mask[availableInstanceCount, occupiedInstanceCount, instances[id, billingItem[description, hourlyRecurringFee]], instanceCount, backendRouter[datacenter]]""" results = self.client.call('Account', 'getReservedCapacityGroups', mask=mask) return results
[docs] def get_object(self, identifier, mask=None): """Get a Reserved Capacity Group :param int identifier: Id of the SoftLayer_Virtual_ReservedCapacityGroup :param string mask: override default object Mask """ if mask is None: mask = "mask[instances[billingItem[item[keyName],category], guest], backendRouter[datacenter]]" result = self.client.call(self.rcg_service, 'getObject', id=identifier, mask=mask) return result
[docs] def get_create_options(self): """List available reserved capacity plans""" mask = "mask[attributes,prices[pricingLocationGroup]]" results = self.ordering_manager.list_items(self.capacity_package, mask=mask) return results
[docs] def get_available_routers(self, dc=None): """Pulls down all backendRouterIds that are available :param string dc: A specific location to get routers for, like 'dal13'. :returns list: A list of locations where RESERVED_CAPACITY can be ordered. """ mask = "mask[locations]" # Step 1, get the package id package = self.ordering_manager.get_package_by_key(self.capacity_package, mask="id") # Step 2, get the regions this package is orderable in regions = self.client.call('Product_Package', 'getRegions', id=package['id'], mask=mask, iter=True) _filter = None routers = {} if dc is not None: _filter = {'datacenterName': {'operation': dc}} # Step 3, for each location in each region, get the pod details, which contains the router id pods = self.client.call('Network_Pod', 'getAllObjects', filter=_filter, iter=True) for region in regions: routers[region['keyname']] = [] for location in region['locations']: location['location']['pods'] = [] for pod in pods: if pod['datacenterName'] == location['location']['name']: location['location']['pods'].append(pod) # Step 4, return the data. return regions
[docs] def create(self, name, backend_router_id, flavor, instances, test=False): """Orders a Virtual_ReservedCapacityGroup :param string name: Name for the new reserved capacity :param int backend_router_id: This selects the pod. See create_options for a list :param string flavor: Capacity KeyName, see create_options for a list :param int instances: Number of guest this capacity can support :param bool test: If True, don't actually order, just test. """ # Since orderManger needs a DC id, just send in 0, the API will ignore it args = (self.capacity_package, 0, [flavor]) extras = {"backendRouterId": backend_router_id, "name": name} kwargs = { 'extras': extras, 'quantity': instances, 'complex_type': 'SoftLayer_Container_Product_Order_Virtual_ReservedCapacity', 'hourly': True } if test: receipt = self.ordering_manager.verify_order(*args, **kwargs) else: receipt = self.ordering_manager.place_order(*args, **kwargs) return receipt
[docs] def create_guest(self, capacity_id, test, guest_object): """Turns an empty Reserve Capacity into a real Virtual Guest :param int capacity_id: ID of the RESERVED_CAPACITY_GROUP to create this guest into :param bool test: True will use verifyOrder, False will use placeOrder :param dictionary guest_object: Below is the minimum info you need to send in guest_object = { 'domain': 'test.com', 'hostname': 'A1538172419', 'os_code': 'UBUNTU_LATEST_64', 'primary_disk': '25', } """ vs_manager = VSManager(self.client) mask = "mask[instances[id, billingItem[id, item[id,keyName]]], backendRouter[id, datacenter[name]]]" capacity = self.get_object(capacity_id, mask=mask) try: capacity_flavor = capacity['instances'][0]['billingItem']['item']['keyName'] flavor = _flavor_string(capacity_flavor, guest_object['primary_disk']) except KeyError as ex: raise SoftLayerError("Unable to find capacity Flavor.") from ex guest_object['flavor'] = flavor guest_object['datacenter'] = capacity['backendRouter']['datacenter']['name'] # Reserved capacity only supports SAN as of 20181008 guest_object['local_disk'] = False # Reserved capacity only supports monthly ordering via Virtual_Guest::generateOrderTemplate # Hourly ordering would require building out the order manually. guest_object['hourly'] = False template = vs_manager.verify_create_instance(**guest_object) template['reservedCapacityId'] = capacity_id if guest_object.get('ipv6'): ipv6_price = self.ordering_manager.get_price_id_list('PUBLIC_CLOUD_SERVER', ['1_IPV6_ADDRESS']) template['prices'].append({'id': ipv6_price[0]}) if test: result = self.client.call('Product_Order', 'verifyOrder', template) else: result = self.client.call('Product_Order', 'placeOrder', template) return result
def _flavor_string(capacity_key, primary_disk): """Removed the _X_YEAR_TERM from capacity_key and adds the primary disk size, creating the flavor keyName This will work fine unless 10 year terms are invented... or flavor format changes... """ flavor = "%sX%s" % (capacity_key[:-12], primary_disk) return flavor