forked from softlayer/softlayer-python
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvs_capacity.py
177 lines (141 loc) · 7.38 KB
/
vs_capacity.py
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
175
176
177
"""
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, no-self-use
LOGGER = logging.getLogger(__name__)
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.
"""
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'] = []
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 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