Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions SoftLayer/CLI/modules/cci.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
reboot Reboots a running CCI
reload Reload the OS on a CCI based on its current configuration
resume Resumes a paused CCI
upgrade Upgrades parameters of a CCI

For several commands, <identifier> will be asked for. This can be the id,
hostname or the ip address for a CCI.
Expand Down Expand Up @@ -1016,3 +1017,96 @@ def execute(self, args):
t.add_row(['transaction_id', capture['id']])
t.add_row(['all_disks', additional_disks])
return t


class UpgradeCCI(CLIRunnable):
"""
usage: sl cci upgrade <identifier> [options]

Upgrade parameters of an CCI

Options:
--cpu=CPU Number of CPU cores
--memory=MEMORY Memory in megabytes
--network=MBPS Network port speed in Mbps
--disk=SIZE... Disks. Can be specified multiple times
--san Use SAN storage instead of local disk. Applies to
all disks specified with --disk.
--reboot Soft Reboot of CCI
"""

action = 'upgrade'
options = ['confirm']

def execute(self, args):
cci = CCIManager(self.client)
data = {}
data['cpus'] = args.get('--cpu')
data['memory'] = args.get('--memory')
data['nic_speed'] = args.get('--network')
instance_id = args.get('<identifier>')
if not instance_id:
raise ArgumentError('CCI ID must be provided')
reboot = False
if args['--reboot']:
reboot = True
data['local_disk'] = True
data['disk'] = ""
# Disks will be a comma-separated list. Let's make it a real list.
if isinstance(args.get('--disk'), str):
args['--disk'] = args.get('--disk').split(',')
data['disk'] = args['--disk']
if args['--san']:
data['local_disk'] = False
if data['local_disk']:
if len(data['disk']) > 2:
raise ArgumentError( \
'Maximum 2 Disks are Allowed for Local')
elif len(data['disk']) > 5:
raise ArgumentError('Maximum 5 Disks are Allowed for SAN')
if data['memory']:
data['memory'] = int(data['memory']) / 1024
if data['disk']:
raise NotImplementedError('Disk Upgrade yet to implement')
if args['--really'] or confirm(
"This action will incur charges on your account. "
"Continue?"):
item_id = []
try:
package_items = cci.get_package_items_for_virtual_guest()
if data['cpus']:
item_id.append({'id': self.get_item_id_for_upgrade(
package_items, 'cpus', data['cpus'])})
if data['memory']:
item_id.append({'id': self.get_item_id_for_upgrade(
package_items, 'memory', data['memory'])})
if data['nic_speed']:
item_id.append({'id': self.get_item_id_for_upgrade(
package_items, 'nic_speed',
data['nic_speed'])})
cci.upgrade(instance_id, item_id)
except:
raise CLIAbort('CCI Upgrade Failed')

def get_item_id_for_upgrade(self, package_items, option, value):
"""
Find the item ids for the parameters you want to upgrade to.
:param list package_items: Contains all the items related to an CCI
:param string option: Describes type of paramter to be upgraded
:param int value: The value of the parameter to be upgraded
"""
id = {'memory': 3, 'cpus': 80, 'nic_speed': 26,
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use id as object or function name. It's might confuse with built-in python id function. Can you use plural ids?

'First Disk': 81, 'Second Disk': 82, 'Third Disk': 92,
'Fourth Disk': 93, 'Fifth Disk': 116}
f = 0
for item in package_items:
if len(filter(lambda x: x.get('id') == id[option], \
item['categories'])) \
and item.get('capacity') == str(value):
if option == 'cpus' or option =='nic_speed':
if f == 1:
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this f? I'm unable to infer its purpose.

return item['prices'][0]['id']
else:
f = f + 1
else:
return item['prices'][0]['id']
34 changes: 33 additions & 1 deletion SoftLayer/managers/cci.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import socket
from time import sleep
from itertools import repeat

import datetime
from SoftLayer.utils import NestedDict, query_filter, IdentifierMixin, lookup


Expand Down Expand Up @@ -484,3 +484,35 @@ def capture(self, instance_id, name, additional_disks=False, notes=None):

return self.guest.createArchiveTransaction(
name, disks, notes, id=instance_id)

def upgrade(self, instance_id, item_id, reboot = False):
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CCIManager is an abstract interface to manage CCIs. To remain abstract it has to hide details like item_id. Just like change_port_speed() function, I think we should provide, upgrade_cpus(), upgrade_memory().

"""
Upgrades a CCI instane
:param int instance_id: Instane id of te CCI to be upgraded
:param int cpus: The number of virtual CPUs to upgrade to
of a CCI instance.
:param int memory: RAM of the CCI to be upgraded to.
:param bool local_disk: Flag to indicate if this should be a local disk
(default) or a SAN disk.
:param list disks: A list of disk capacities for this server
:param bool reboot: Flag to indicate weather to reboot or
not upon upgrade
:param int nic_speed: The port speed to set
"""
orderClient = self.client['Product_Order']
orderContainer = {}
orderContainer['complexType'] = \
'SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade'
orderContainer['virtualGuests'] = [{'id': int(instance_id)}]
orderContainer['prices'] = item_id
orderContainer['properties'] = [{'name': 'MAINTENANCE_WINDOW',
'value': str(datetime.datetime.now())}]
orderClient.verifyOrder(orderContainer)
orderClient.placeOrder(orderContainer)
if reboot:
self.guest.rebootSoft(id=int(instance_id))

def get_package_items_for_virtual_guest(self):
mask = "mask[capacity,prices.id,categories[name,id]]"
package = self.client['Product_Package']
return package.getItems(id=46, mask=mask)
1 change: 1 addition & 0 deletions SoftLayer/tests/fixtures/Virtual_Guest.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,5 +214,6 @@
generateOrderTemplate = {}
setUserMetadata = ['meta']
reloadOperatingSystem = 'OK'
rebootSoft = True

createArchiveTransaction = {}
36 changes: 36 additions & 0 deletions SoftLayer/tests/managers/cci_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,42 @@ def test_captures(self):
archive.called_once_with('a', [{"device": 0, "uuid": 1},
{"device": 2, "uuid": 2}], "", id=1)

def test_upgrade(self):
# Testing Upgrade
orderClient = self.client['Product_Order']

# test single upgrade
item_ids = [{'id': 1024}]
self.cci.upgrade(1, item_ids)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are we testing here? Nothing seems to be getting asserted after this.


# test single upgrade with rebot
item_ids = [{'id': 1024}]
self.cci.upgrade(1, item_ids, reboot = True)

# Now test a blank upgrade
self.assertTrue(self.cci.upgrade, 1)

# Finally, test a full Upgrade
item_ids = [{'id': 1}, {'id': 2}, {'id': 3}]
self.cci.upgrade(1, item_ids)
order = self.test_ordercontainer_options()
orderClient.verifyOrder.called_once_with(order)
orderClient.placeOrder.called_once_with(order)

def test_package_ids_for_virtual_guest(self):
result = self.cci.get_package_items_for_virtual_guest()[0]
self.assertEqual(4444, result['prices'][0]['id'])

def test_ordercontainer_options(self):
orderContainer = {}
orderContainer['complexType'] = \
'SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade'
orderContainer['virtualGuests'] = [{'id': 1}]
orderContainer['prices'] = [{'id': 1645}]
orderContainer['properties'] = [{'name': 'MAINTENANCE_WINDOW',
'value': '2014-03-21 03:12:47.942307'}]
return orderContainer


class CCIWaitReadyGoTests(unittest.TestCase):

Expand Down