Repository: softlayer/softlayer-python
Pull request #1032 (2018-09-03 22:09:44)

Fo vs upgrade with flavor
fixed vs upgrade with flavor data  https://github.com/softlayer/softlayer-python/issues/1028


Patch:
diff --git a/SoftLayer/CLI/virt/upgrade.py b/SoftLayer/CLI/virt/upgrade.py
index 419456f9..039e7cbf 100644
--- a/SoftLayer/CLI/virt/upgrade.py
+++ b/SoftLayer/CLI/virt/upgrade.py
@@ -21,15 +21,17 @@
               help="CPU core will be on a dedicated host server.")
 @click.option('--memory', type=virt.MEM_TYPE, help="Memory in megabytes")
 @click.option('--network', type=click.INT, help="Network port speed in Mbps")
+@click.option('--flavor', type=click.STRING, help="Flavor keyName\n"
+                                                  "Do not use --memory, --cpu or --private, if you are using flavors")
 @environment.pass_env
-def cli(env, identifier, cpu, private, memory, network):
+def cli(env, identifier, cpu, private, memory, network, flavor):
     """Upgrade a virtual server."""
 
     vsi = SoftLayer.VSManager(env.client)
 
-    if not any([cpu, memory, network]):
+    if not any([cpu, memory, network, flavor]):
         raise exceptions.ArgumentError(
-            "Must provide [--cpu], [--memory], or [--network] to upgrade")
+            "Must provide [--cpu], [--memory], [--network], or [--flavor] to upgrade")
 
     if private and not cpu:
         raise exceptions.ArgumentError(
@@ -48,5 +50,6 @@ def cli(env, identifier, cpu, private, memory, network):
                        cpus=cpu,
                        memory=memory,
                        nic_speed=network,
-                       public=not private):
+                       public=not private,
+                       preset=flavor):
         raise exceptions.CLIAbort('VS Upgrade Failed')
diff --git a/SoftLayer/fixtures/SoftLayer_Product_Package.py b/SoftLayer/fixtures/SoftLayer_Product_Package.py
index 9b5d5374..2642b77e 100644
--- a/SoftLayer/fixtures/SoftLayer_Product_Package.py
+++ b/SoftLayer/fixtures/SoftLayer_Product_Package.py
@@ -1340,3 +1340,32 @@
         }]
     }]
 }]
+
+getActivePresets = [
+    {
+        "description": "M1.64x512x25",
+        "id": 799,
+        "isActive": "1",
+        "keyName": "M1_64X512X25",
+        "name": "M1.64x512x25",
+        "packageId": 835
+    },
+    {
+        "description": "M1.56x448x100",
+        "id": 797,
+        "isActive": "1",
+        "keyName": "M1_56X448X100",
+        "name": "M1.56x448x100",
+        "packageId": 835
+    },
+    {
+        "description": "M1.64x512x100",
+        "id": 801,
+        "isActive": "1",
+        "keyName": "M1_64X512X100",
+        "name": "M1.64x512x100",
+        "packageId": 835
+    }
+]
+
+getAccountRestrictedActivePresets = []
diff --git a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
index 776db877..ac20acb9 100644
--- a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
+++ b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
@@ -14,6 +14,10 @@
             {'nextInvoiceTotalRecurringAmount': 1},
             {'nextInvoiceTotalRecurringAmount': 1},
         ],
+        'package': {
+            "id": 835,
+            "keyName": "PUBLIC_CLOUD_SERVER"
+        },
         'orderItem': {
             'order': {
                 'userRecord': {
diff --git a/SoftLayer/managers/vs.py b/SoftLayer/managers/vs.py
index 059f0606..03595d8d 100644
--- a/SoftLayer/managers/vs.py
+++ b/SoftLayer/managers/vs.py
@@ -51,6 +51,7 @@ def __init__(self, client, ordering_manager=None):
         self.client = client
         self.account = client['Account']
         self.guest = client['Virtual_Guest']
+        self.package_svc = client['Product_Package']
         self.resolvers = [self._get_ids_from_ip, self._get_ids_from_hostname]
         if ordering_manager is None:
             self.ordering_manager = ordering.OrderingManager(client)
@@ -209,6 +210,7 @@ def get_instance(self, instance_id, **kwargs):
                 'maxMemory,'
                 'datacenter,'
                 'activeTransaction[id, transactionStatus[friendlyName,name]],'
+                'lastTransaction[transactionStatus],'
                 'lastOperatingSystemReload.id,'
                 'blockDevices,'
                 'blockDeviceTemplateGroup[id, name, globalIdentifier],'
@@ -225,6 +227,7 @@ def get_instance(self, instance_id, **kwargs):
                 'hourlyBillingFlag,'
                 'userData,'
                 '''billingItem[id,nextInvoiceTotalRecurringAmount,
+                               package[id,keyName],
                                children[categoryCode,nextInvoiceTotalRecurringAmount],
                                orderItem[id,
                                          order.userRecord[username],
@@ -803,7 +806,7 @@ def capture(self, instance_id, name, additional_disks=False, notes=None):
             name, disks_to_capture, notes, id=instance_id)
 
     def upgrade(self, instance_id, cpus=None, memory=None,
-                nic_speed=None, public=True):
+                nic_speed=None, public=True, preset=None):
         """Upgrades a VS instance.
 
         Example::
@@ -817,6 +820,7 @@ def upgrade(self, instance_id, cpus=None, memory=None,
         :param int instance_id: Instance id of the VS to be upgraded
         :param int cpus: The number of virtual CPUs to upgrade to
                             of a VS instance.
+        :param string preset: preset assigned to the vsi
         :param int memory: RAM of the VS to be upgraded to.
         :param int nic_speed: The port speed to set
         :param bool public: CPU will be in Private/Public Node.
@@ -826,9 +830,28 @@ def upgrade(self, instance_id, cpus=None, memory=None,
         upgrade_prices = self._get_upgrade_prices(instance_id)
         prices = []
 
-        for option, value in {'cpus': cpus,
-                              'memory': memory,
-                              'nic_speed': nic_speed}.items():
+        data = {'nic_speed': nic_speed}
+
+        if cpus is not None and preset is not None:
+            raise exceptions.SoftLayerError("Do not use cpu, private and memory if you are using flavors")
+        data['cpus'] = cpus
+
+        if memory is not None and preset is not None:
+            raise exceptions.SoftLayerError("Do not use memory, private or cpu if you are using flavors")
+        data['memory'] = memory
+
+        maintenance_window = datetime.datetime.now(utils.UTC())
+        order = {
+            'complexType': 'SoftLayer_Container_Product_Order_Virtual_Guest_'
+                           'Upgrade',
+            'properties': [{
+                'name': 'MAINTENANCE_WINDOW',
+                'value': maintenance_window.strftime("%Y-%m-%d %H:%M:%S%z")
+            }],
+            'virtualGuests': [{'id': int(instance_id)}],
+        }
+
+        for option, value in data.items():
             if not value:
                 continue
             price_id = self._get_price_id_for_upgrade_option(upgrade_prices,
@@ -841,19 +864,13 @@ def upgrade(self, instance_id, cpus=None, memory=None,
                     "Unable to find %s option with value %s" % (option, value))
 
             prices.append({'id': price_id})
+        order['prices'] = prices
 
-        maintenance_window = datetime.datetime.now(utils.UTC())
-        order = {
-            'complexType': 'SoftLayer_Container_Product_Order_Virtual_Guest_'
-                           'Upgrade',
-            'prices': prices,
-            'properties': [{
-                'name': 'MAINTENANCE_WINDOW',
-                'value': maintenance_window.strftime("%Y-%m-%d %H:%M:%S%z")
-            }],
-            'virtualGuests': [{'id': int(instance_id)}],
-        }
-        if prices:
+        if preset is not None:
+            vs_object = self.get_instance(instance_id)['billingItem']['package']
+            order['presetId'] = self.ordering_manager.get_preset_by_key(vs_object['keyName'], preset)['id']
+
+        if prices or preset:
             self.client['Product_Order'].placeOrder(order)
             return True
         return False


Test patch:
diff --git a/tests/CLI/modules/vs_tests.py b/tests/CLI/modules/vs_tests.py
index c976a952..28496344 100644
--- a/tests/CLI/modules/vs_tests.py
+++ b/tests/CLI/modules/vs_tests.py
@@ -901,6 +901,23 @@ def test_upgrade(self, confirm_mock):
         self.assertIn({'id': 1122}, order_container['prices'])
         self.assertEqual(order_container['virtualGuests'], [{'id': 100}])
 
+    @mock.patch('SoftLayer.CLI.formatting.confirm')
+    def test_upgrade_with_flavor(self, confirm_mock):
+        confirm_mock.return_value = True
+        result = self.run_command(['vs', 'upgrade', '100', '--flavor=M1_64X512X100'])
+        self.assert_no_fail(result)
+        self.assert_called_with('SoftLayer_Product_Order', 'placeOrder')
+        call = self.calls('SoftLayer_Product_Order', 'placeOrder')[0]
+        order_container = call.args[0]
+        self.assertEqual(799, order_container['presetId'])
+        self.assertIn({'id': 100}, order_container['virtualGuests'])
+        self.assertEqual(order_container['virtualGuests'], [{'id': 100}])
+
+    def test_upgrade_with_cpu_memory_and_flavor(self):
+        result = self.run_command(['vs', 'upgrade', '100', '--cpu=4',
+                                   '--memory=1024', '--flavor=M1_64X512X100'])
+        self.assertEqual("Do not use cpu, private and memory if you are using flavors", str(result.exception))
+
     def test_edit(self):
         result = self.run_command(['vs', 'edit',
                                    '--domain=example.com',
diff --git a/tests/managers/vs_tests.py b/tests/managers/vs_tests.py
index 456b5cbc..97b6c5c4 100644
--- a/tests/managers/vs_tests.py
+++ b/tests/managers/vs_tests.py
@@ -879,6 +879,22 @@ def test_upgrade_full(self):
         self.assertIn({'id': 1122}, order_container['prices'])
         self.assertEqual(order_container['virtualGuests'], [{'id': 1}])
 
+    def test_upgrade_with_flavor(self):
+        # Testing Upgrade with parameter preset
+        result = self.vs.upgrade(1,
+                                 preset="M1_64X512X100",
+                                 nic_speed=1000,
+                                 public=True)
+
+        self.assertEqual(result, True)
+        self.assert_called_with('SoftLayer_Product_Order', 'placeOrder')
+        call = self.calls('SoftLayer_Product_Order', 'placeOrder')[0]
+        order_container = call.args[0]
+        self.assertEqual(799, order_container['presetId'])
+        self.assertIn({'id': 1}, order_container['virtualGuests'])
+        self.assertIn({'id': 1122}, order_container['prices'])
+        self.assertEqual(order_container['virtualGuests'], [{'id': 1}])
+
     def test_upgrade_dedicated_host_instance(self):
         mock = self.set_mock('SoftLayer_Virtual_Guest', 'getUpgradeItemPrices')
         mock.return_value = fixtures.SoftLayer_Virtual_Guest.DEDICATED_GET_UPGRADE_ITEM_PRICES