File: vs_capacity.py

package info (click to toggle)
python-softlayer 5.6.4-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 3,368 kB
  • sloc: python: 36,501; makefile: 134; sh: 85
file content (174 lines) | stat: -rw-r--r-- 7,277 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
"""
    SoftLayer.vs_capacity
    ~~~~~~~~~~~~~~~~~~~~~~~
    Reserved Capacity Manager and helpers

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

import logging
import SoftLayer

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, no-self-use

LOGGER = logging.getLogger(__name__)


class CapacityManager(utils.IdentifierMixin, object):
    """Manages SoftLayer Reserved Capacity Groups.

        Product Information

        - https://console.bluemix.net/docs/vsi/vsi_about_reserved.html
        - 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.
    """

    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)

    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

    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

    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

    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'] = list()
                for pod in pods:
                    if pod['datacenterName'] == location['location']['name']:
                        location['location']['pods'].append(pod)

        # Step 4, return the data.
        return regions

    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

    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:
            raise SoftLayer.SoftLayerError("Unable to find capacity Flavor.")

        guest_object['flavor'] = flavor
        guest_object['datacenter'] = capacity['backendRouter']['datacenter']['name']

        # Reserved capacity only supports SAN as of 20181008
        guest_object['local_disk'] = 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