def execute(self, args):
        cci = CCIManager(self.client)

        cci_id = resolve_id(cci.resolve_ids, args.get('<identifier>'), 'CCI')
        ready = cci.wait_for_transaction(cci_id, int(args.get('--wait') or 0))

        if ready:
            return "READY"
        else:
            raise CLIAbort("Instance %s not ready" % cci_id)
Example #2
0
class CCIWaitReadyGoTests(unittest.TestCase):

    def setUp(self):
        self.client = MagicMock()
        self.cci = CCIManager(self.client)
        self.guestObject = self.client['Virtual_Guest'].getObject

    @patch('SoftLayer.managers.cci.CCIManager.wait_for_ready')
    def test_wait_interface(self, ready):
        # verify interface to wait_for_ready is intact
        self.cci.wait_for_transaction(1, 1)
        ready.assert_called_once_with(1, 1, delay=1, pending=True)

    def test_active_not_provisioned(self):
        # active transaction and no provision date should be false
        self.guestObject.side_effect = [
            {'activeTransaction': {'id': 1}},
        ]
        value = self.cci.wait_for_ready(1, 1)
        self.assertFalse(value)

    def test_active_and_provisiondate(self):
        # active transaction and provision date should be True
        self.guestObject.side_effect = [
            {'activeTransaction': {'id': 1},
             'provisionDate': 'aaa'},
        ]
        value = self.cci.wait_for_ready(1, 1)
        self.assertTrue(value)

    def test_active_provision_pending(self):
        # active transaction and provision date
        # and pending should be false
        self.guestObject.side_effect = [
            {'activeTransaction': {'id': 1},
             'provisionDate': 'aaa'},
        ]
        value = self.cci.wait_for_ready(1, 1, pending=True)
        self.assertFalse(value)

    def test_active_reload(self):
        # actively running reload
        self.guestObject.side_effect = [
            {
                'activeTransaction': {'id': 1},
                'provisionDate': 'aaa',
                'lastOperatingSystemReload': {'id': 1},
            },
        ]
        value = self.cci.wait_for_ready(1, 1)
        self.assertFalse(value)

    def test_reload_no_pending(self):
        # reload complete, maintance transactions
        self.guestObject.side_effect = [
            {
                'activeTransaction': {'id': 2},
                'provisionDate': 'aaa',
                'lastOperatingSystemReload': {'id': 1},
            },
        ]
        value = self.cci.wait_for_ready(1, 1)
        self.assertTrue(value)

    def test_reload_pending(self):
        # reload complete, pending maintance transactions
        self.guestObject.side_effect = [
            {
                'activeTransaction': {'id': 2},
                'provisionDate': 'aaa',
                'lastOperatingSystemReload': {'id': 1},
            },
        ]
        value = self.cci.wait_for_ready(1, 1, pending=True)
        self.assertFalse(value)

    @patch('SoftLayer.managers.cci.sleep')
    def test_ready_iter_once_incomplete(self, _sleep):
        self.guestObject = self.client['Virtual_Guest'].getObject

        # no iteration, false
        self.guestObject.side_effect = [
            {'activeTransaction': {'id': 1}},
        ]
        value = self.cci.wait_for_ready(1, 1)
        self.assertFalse(value)
        self.assertFalse(_sleep.called)

    @patch('SoftLayer.managers.cci.sleep')
    def test_iter_once_complete(self, _sleep):
        # no iteration, true
        self.guestObject.side_effect = [
            {'provisionDate': 'aaa'},
        ]
        value = self.cci.wait_for_ready(1, 1)
        self.assertTrue(value)
        self.assertFalse(_sleep.called)

    @patch('SoftLayer.managers.cci.sleep')
    def test_iter_four_complete(self, _sleep):
        # test 4 iterations with positive match
        self.guestObject.side_effect = [
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'provisionDate': 'aaa'},
        ]

        value = self.cci.wait_for_ready(1, 4)
        self.assertTrue(value)
        _sleep.assert_has_calls([call(1), call(1), call(1)])
        self.guestObject.assert_has_calls([
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
        ])

    @patch('SoftLayer.managers.cci.sleep')
    def test_iter_two_incomplete(self, _sleep):
        # test 2 iterations, with no matches
        self.guestObject.side_effect = [
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'provisionDate': 'aaa'}
        ]
        value = self.cci.wait_for_ready(1, 2)
        self.assertFalse(value)
        _sleep.assert_called_once_with(1)
        self.guestObject.assert_has_calls([
            call(id=1, mask=ANY), call(id=1, mask=ANY),
        ])

    @patch('SoftLayer.managers.cci.sleep')
    def test_iter_ten_incomplete(self, _sleep):
        # 10 iterations at 10 second sleeps with no
        # matching values.
        self.guestObject.side_effect = [
            {},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
        ]
        value = self.cci.wait_for_ready(1, 10, delay=10)
        self.assertFalse(value)
        self.guestObject.assert_has_calls([
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
        ])
        # should only be 9 calls to sleep, last iteration
        # should return a value and skip the sleep
        _sleep.assert_has_calls([
            call(10), call(10), call(10), call(10), call(10),
            call(10), call(10), call(10), call(10)])
Example #3
0
    def on_post(self, req, resp, tenant_id, instance_id):
        body = json.loads(req.stream.read().decode())

        if len(body) == 0:
            return bad_request(resp, message="Malformed request body")

        vg_client = req.env['sl_client']['Virtual_Guest']
        cci = CCIManager(req.env['sl_client'])

        try:
            instance_id = int(instance_id)
        except ValueError:
            return not_found(resp, "Invalid instance ID specified.")

        instance = cci.get_instance(instance_id)

        if 'pause' in body or 'suspend' in body:
            try:
                vg_client.pause(id=instance_id)
            except SoftLayerAPIError as e:
                if 'Unable to pause instance' in e.faultString:
                    return duplicate(resp, e.faultString)
                raise
            resp.status = 202
            return
        elif 'unpause' in body or 'resume' in body:
            vg_client.resume(id=instance_id)
            resp.status = 202
            return
        elif 'reboot' in body:
            if body['reboot'].get('type') == 'SOFT':
                vg_client.rebootSoft(id=instance_id)
            elif body['reboot'].get('type') == 'HARD':
                vg_client.rebootHard(id=instance_id)
            else:
                vg_client.rebootDefault(id=instance_id)
            resp.status = 202
            return
        elif 'os-stop' in body:
            vg_client.powerOff(id=instance_id)
            resp.status = 202
            return
        elif 'os-start' in body:
            vg_client.powerOn(id=instance_id)
            resp.status = 202
            return
        elif 'createImage' in body:
            image_name = body['createImage']['name']
            disks = []

            for disk in filter(lambda x: x['device'] == '0',
                               instance['blockDevices']):
                disks.append(disk)

            try:
                vg_client.createArchiveTransaction(
                    image_name,
                    disks,
                    "Auto-created by OpenStack compatibility layer",
                    id=instance_id,
                )
                # Workaround for not having an image guid until the image is
                # fully created. TODO: Fix this
                cci.wait_for_transaction(instance_id, 300)
                _filter = {
                    'privateBlockDeviceTemplateGroups': {
                        'name': {'operation': image_name},
                        'createDate': {
                            'operation': 'orderBy',
                            'options': [{'name': 'sort', 'value': ['DESC']}],
                        }
                    }}

                acct = req.env['sl_client']['Account']
                matching_image = acct.getPrivateBlockDeviceTemplateGroups(
                    mask='id, globalIdentifier', filter=_filter, limit=1)
                image_guid = matching_image.get('globalIdentifier')

                url = self.app.get_endpoint_url('image', req, 'v2_image',
                                                image_guid=image_guid)

                resp.status = 202
                resp.set_header('location', url)
            except SoftLayerAPIError as e:
                compute_fault(resp, e.faultString)
            return
        elif 'os-getConsoleOutput' in body:
            resp.status = 501
            return
        elif 'resize' in body:
            flavor_id = int(body['resize'].get('flavorRef'))
            if flavor_id not in FLAVORS:
                return bad_request(resp,
                                   message="Invalid flavor id in the "
                                   "request body")
            flavor = FLAVORS[flavor_id]
            cci.upgrade(instance_id, cpus=flavor['cpus'],
                        memory=flavor['ram'] / 1024)
            resp.status = 202
            return
        elif 'confirmResize' in body:
            resp.status = 204
            return

        return bad_request(resp,
                           message="There is no such action: %s" %
                           list(body.keys()), code=400)
Example #4
0
    def on_post(self, req, resp, tenant_id, instance_id):
        body = json.loads(req.stream.read().decode())

        if len(body) == 0:
            return bad_request(resp, message="Malformed request body")

        vg_client = req.env['sl_client']['Virtual_Guest']
        cci = CCIManager(req.env['sl_client'])

        try:
            instance_id = int(instance_id)
        except ValueError:
            return not_found(resp, "Invalid instance ID specified.")

        instance = cci.get_instance(instance_id)

        if 'pause' in body or 'suspend' in body:
            try:
                vg_client.pause(id=instance_id)
            except SoftLayerAPIError as e:
                if 'Unable to pause instance' in e.faultString:
                    return duplicate(resp, e.faultString)
                raise
            resp.status = 202
            return
        elif 'unpause' in body or 'resume' in body:
            vg_client.resume(id=instance_id)
            resp.status = 202
            return
        elif 'reboot' in body:
            if body['reboot'].get('type') == 'SOFT':
                vg_client.rebootSoft(id=instance_id)
            elif body['reboot'].get('type') == 'HARD':
                vg_client.rebootHard(id=instance_id)
            else:
                vg_client.rebootDefault(id=instance_id)
            resp.status = 202
            return
        elif 'os-stop' in body:
            vg_client.powerOff(id=instance_id)
            resp.status = 202
            return
        elif 'os-start' in body:
            vg_client.powerOn(id=instance_id)
            resp.status = 202
            return
        elif 'createImage' in body:
            image_name = body['createImage']['name']
            disks = []

            for disk in filter(lambda x: x['device'] == '0',
                               instance['blockDevices']):
                disks.append(disk)

            try:
                vg_client.createArchiveTransaction(
                    image_name,
                    disks,
                    "Auto-created by OpenStack compatibility layer",
                    id=instance_id,
                )
                # Workaround for not having an image guid until the image is
                # fully created. TODO: Fix this
                cci.wait_for_transaction(instance_id, 300)
                _filter = {
                    'privateBlockDeviceTemplateGroups': {
                        'name': {
                            'operation': image_name
                        },
                        'createDate': {
                            'operation': 'orderBy',
                            'options': [{
                                'name': 'sort',
                                'value': ['DESC']
                            }],
                        }
                    }
                }

                acct = req.env['sl_client']['Account']
                matching_image = acct.getPrivateBlockDeviceTemplateGroups(
                    mask='id, globalIdentifier', filter=_filter, limit=1)
                image_guid = matching_image.get('globalIdentifier')

                url = self.app.get_endpoint_url('image',
                                                req,
                                                'v2_image',
                                                image_guid=image_guid)

                resp.status = 202
                resp.set_header('location', url)
            except SoftLayerAPIError as e:
                compute_fault(resp, e.faultString)
            return
        elif 'os-getConsoleOutput' in body:
            resp.status = 501
            return

        return bad_request(resp,
                           message="There is no such action: %s" %
                           list(body.keys()),
                           code=400)
class CCITests(unittest.TestCase):

    def setUp(self):
        self.client = MagicMock()
        self.cci = CCIManager(self.client)

    def test_list_instances(self):
        mcall = call(mask=ANY, filter={})
        service = self.client['Account']
        service.getVirtualGuests = account_mock.getVirtualGuests_Mock()
        hourly_mock = account_mock.getHourlyVirtualGuests_Mock()
        service.getHourlyVirtualGuests = hourly_mock
        monthly_mock = account_mock.getMonthlyVirtualGuests_Mock()
        service.getMonthlyVirtualGuests = monthly_mock

        list_expected_ids = [100, 104]
        hourly_expected_ids = [104]
        monthly_expected_ids = [100]

        results = self.cci.list_instances(hourly=True, monthly=True)
        service.getVirtualGuests.assert_has_calls(mcall)
        for result in results:
            self.assertIn(result['id'], list_expected_ids)

        result = self.cci.list_instances(hourly=False, monthly=False)
        service.getVirtualGuests.assert_has_calls(mcall)
        for result in results:
            self.assertIn(result['id'], list_expected_ids)

        results = self.cci.list_instances(hourly=False, monthly=True)
        service.getMonthlyVirtualGuests.assert_has_calls(mcall)
        for result in results:
            self.assertIn(result['id'], monthly_expected_ids)

        results = self.cci.list_instances(hourly=True, monthly=False)
        service.getHourlyVirtualGuests.assert_has_calls(mcall)
        for result in results:
            self.assertIn(result['id'], hourly_expected_ids)

    def test_list_instances_with_filters(self):
        self.cci.list_instances(
            hourly=True,
            monthly=True,
            tags=['tag1', 'tag2'],
            cpus=2,
            memory=1024,
            hostname='hostname',
            domain='example.com',
            local_disk=True,
            datacenter='dal05',
            nic_speed=100,
            public_ip='1.2.3.4',
            private_ip='4.3.2.1',
        )

        service = self.client['Account']
        service.getVirtualGuests.assert_has_calls(call(
            filter={
                'virtualGuests': {
                    'datacenter': {
                        'name': {'operation': '_= dal05'}},
                    'domain': {'operation': '_= example.com'},
                    'tagReferences': {
                        'tag': {'name': {
                            'operation': 'in',
                            'options': [{
                                'name': 'data', 'value': ['tag1', 'tag2']}]}}},
                    'maxCpu': {'operation': 2},
                    'localDiskFlag': {'operation': True},
                    'maxMemory': {'operation': 1024},
                    'hostname': {'operation': '_= hostname'},
                    'networkComponents': {'maxSpeed': {'operation': 100}},
                    'primaryIpAddress': {'operation': '_= 1.2.3.4'},
                    'primaryBackendIpAddress': {'operation': '_= 4.3.2.1'}
                }},
            mask=ANY,
        ))

    def test_resolve_ids_ip(self):
        service = self.client['Account']
        service.getVirtualGuests = account_mock.getVirtualGuests_Mock(100)
        _id = self.cci._get_ids_from_ip('172.16.240.2')
        self.assertEqual(_id, [100])

        _id = self.cci._get_ids_from_ip('nope')
        self.assertEqual(_id, [])

        # Now simulate a private IP test
        service.getVirtualGuests.side_effect = [[], [{'id': 99}]]
        _id = self.cci._get_ids_from_ip('10.0.1.87')
        self.assertEqual(_id, [99])

    def test_resolve_ids_hostname(self):
        service = self.client['Account']
        service.getVirtualGuests = account_mock.getVirtualGuests_Mock(100)
        _id = self.cci._get_ids_from_hostname('cci-test1')
        self.assertEqual(_id, [100])

    def test_get_instance(self):
        service = self.client['Virtual_Guest']
        service.getObject = virtual_guest_mock.getObject_Mock(100)
        result = self.cci.get_instance(100)
        self.client['Virtual_Guest'].getObject.assert_called_once_with(
            id=100, mask=ANY)
        expected = virtual_guest_mock.get_raw_cci_mocks()[100]
        self.assertEqual(expected, result)

    def test_get_create_options(self):
        service = self.client['Virtual_Guest']
        function_mock = virtual_guest_mock.getCreateObjectOptions_Mock()
        service.getCreateObjectOptions = function_mock
        results = self.cci.get_create_options()
        function_mock.assert_called_once_with()

        expected = ['processors', 'memory', 'blockDevices', 'operatingSystems',
                    'networkComponents', 'datacenters']
        method = 'assertItemsEqual'
        if not hasattr(self, method):
            # For Python 3.3 compatibility
            method = 'assertCountEqual'
        f = getattr(self, method)
        f(expected, results.keys())

    def test_cancel_instance(self):
        self.cci.cancel_instance(1)
        self.client['Virtual_Guest'].deleteObject.assert_called_once_with(id=1)

    def test_reload_instance(self):
        post_uri = 'http://test.sftlyr.ws/test.sh'
        self.cci.reload_instance(1, post_uri=post_uri, ssh_keys=[1701])
        service = self.client['Virtual_Guest']
        f = service.reloadOperatingSystem
        f.assert_called_once_with('FORCE',
                                  {'customProvisionScriptUri': post_uri,
                                   'sshKeyIds': [1701]}, id=1)

    @patch('SoftLayer.managers.cci.CCIManager._generate_create_dict')
    def test_create_verify(self, create_dict):
        create_dict.return_value = {'test': 1, 'verify': 1}
        self.cci.verify_create_instance(test=1, verify=1)
        create_dict.assert_called_once_with(test=1, verify=1)
        f = self.client['Virtual_Guest'].generateOrderTemplate
        f.assert_called_once_with({'test': 1, 'verify': 1})

    @patch('SoftLayer.managers.cci.CCIManager._generate_create_dict')
    def test_create_instance(self, create_dict):
        create_dict.return_value = {'test': 1, 'verify': 1}
        self.cci.create_instance(test=1, verify=1)
        create_dict.assert_called_once_with(test=1, verify=1)
        self.client['Virtual_Guest'].createObject.assert_called_once_with(
            {'test': 1, 'verify': 1})

    def test_generate_os_and_image(self):
        self.assertRaises(
            ValueError,
            self.cci._generate_create_dict,
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code=1,
            image_id=1,
        )

    def test_generate_missing(self):
        self.assertRaises(ValueError, self.cci._generate_create_dict)
        self.assertRaises(ValueError, self.cci._generate_create_dict, cpus=1)

    def test_generate_basic(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
        }

        self.assertEqual(data, assert_data)

    def test_generate_monthly(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            hourly=False,
        )

        assert_data = {
            'hourlyBillingFlag': False,
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
        }

        self.assertEqual(data, assert_data)

    def test_generate_image_id(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            image_id="45",
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'blockDeviceTemplateGroup': {"globalIdentifier": "45"},
            'hourlyBillingFlag': True,
        }

        self.assertEqual(data, assert_data)

    def test_generate_dedicated(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            dedicated=True,
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
            'dedicatedAccountHostOnlyFlag': True,
        }

        self.assertEqual(data, assert_data)

    def test_generate_datacenter(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            datacenter="sng01",
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
            'datacenter': {"name": 'sng01'},
        }

        self.assertEqual(data, assert_data)

    def test_generate_public_vlan(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            public_vlan=1,
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
            'primaryNetworkComponent': {"networkVlan": {"id": 1}},
        }

        self.assertEqual(data, assert_data)

    def test_generate_private_vlan(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            private_vlan=1,
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
            'primaryBackendNetworkComponent': {"networkVlan": {"id": 1}},
        }

        self.assertEqual(data, assert_data)

    def test_generate_userdata(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            userdata="ICANHAZCCI",
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
            'userData': [{'value': "ICANHAZCCI"}],
        }

        self.assertEqual(data, assert_data)

    def test_generate_network(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            nic_speed=9001,
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
            'networkComponents': [{'maxSpeed': 9001}],
        }

        self.assertEqual(data, assert_data)

    def test_generate_private_network_only(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            nic_speed=9001,
            private=True
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'privateNetworkOnlyFlag': True,
            'hourlyBillingFlag': True,
            'networkComponents': [{'maxSpeed': 9001}],
        }

        self.assertEqual(data, assert_data)

    def test_generate_post_uri(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            post_uri='https://example.com/boostrap.sh',
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
            'postInstallScriptUri': 'https://example.com/boostrap.sh',
        }

        self.assertEqual(data, assert_data)

    def test_generate_sshkey(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            ssh_keys=[543],
        )

        assert_data = {
            'startCpus': 1,
            'maxMemory': 1,
            'hostname': 'test',
            'domain': 'example.com',
            'localDiskFlag': True,
            'operatingSystemReferenceCode': "STRING",
            'hourlyBillingFlag': True,
            'sshKeys': [{'id': 543}],
        }

        self.assertEqual(data, assert_data)

    def test_generate_no_disks(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING"
        )

        self.assertEqual(data.get('blockDevices'), None)

    def test_generate_single_disk(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            disks=[50]
        )

        assert_data = {
            'blockDevices': [
                {"device": "0", "diskImage": {"capacity": 50}}]
        }

        self.assertTrue(data.get('blockDevices'))
        self.assertEqual(data['blockDevices'], assert_data['blockDevices'])

    def test_generate_multi_disk(self):
        data = self.cci._generate_create_dict(
            cpus=1,
            memory=1,
            hostname='test',
            domain='example.com',
            os_code="STRING",
            disks=[50, 70, 100]
        )

        assert_data = {
            'blockDevices': [
                {"device": "0", "diskImage": {"capacity": 50}},
                {"device": "2", "diskImage": {"capacity": 70}},
                {"device": "3", "diskImage": {"capacity": 100}}]
        }

        self.assertTrue(data.get('blockDevices'))
        self.assertEqual(data['blockDevices'], assert_data['blockDevices'])

    @patch('SoftLayer.managers.cci.sleep')
    def test_wait(self, _sleep):
        guestObject = self.client['Virtual_Guest'].getObject

        # test 4 iterations with positive match
        guestObject.side_effect = [
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'provisionDate': 'aaa'},
            {'provisionDate': 'aaa'}
        ]

        value = self.cci.wait_for_transaction(1, 4)
        self.assertTrue(value)
        _sleep.assert_has_calls([call(1), call(1), call(1)])
        guestObject.assert_has_calls([
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
        ])

        # test 2 iterations, with no matches
        _sleep.reset_mock()
        guestObject.reset_mock()

        guestObject.side_effect = [
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'provisionDate': 'aaa'}
        ]
        value = self.cci.wait_for_transaction(1, 2)
        self.assertFalse(value)
        _sleep.assert_has_calls([call(1), call(1)])
        guestObject.assert_has_calls([
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY)
        ])

        # 10 iterations at 10 second sleeps with no
        # matching values.
        _sleep.reset_mock()
        guestObject.reset_mock()
        guestObject.side_effect = [
            {},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}},
            {'activeTransaction': {'id': 1}}
        ]
        value = self.cci.wait_for_transaction(1, 10, 10)
        self.assertFalse(value)
        guestObject.assert_has_calls([
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY), call(id=1, mask=ANY),
            call(id=1, mask=ANY)
        ])
        _sleep.assert_has_calls([
            call(10), call(10), call(10), call(10), call(10),
            call(10), call(10), call(10), call(10), call(10)])

    def test_change_port_speed_public(self):
        cci_id = 1
        speed = 100
        self.cci.change_port_speed(cci_id, True, speed)

        service = self.client['Virtual_Guest']
        f = service.setPublicNetworkInterfaceSpeed
        f.assert_called_once_with(speed, id=cci_id)

    def test_change_port_speed_private(self):
        cci_id = 2
        speed = 10
        self.cci.change_port_speed(cci_id, False, speed)

        service = self.client['Virtual_Guest']
        f = service.setPrivateNetworkInterfaceSpeed
        f.assert_called_once_with(speed, id=cci_id)

    def test_edit(self):
        # Test editing user data
        service = self.client['Virtual_Guest']

        self.cci.edit(100, userdata='my data')

        service.setUserMetadata.assert_called_once_with(['my data'], id=100)

        # Now test a blank edit
        self.assertTrue(self.cci.edit, 100)

        # Finally, test a full edit
        args = {
            'hostname': 'new-host',
            'domain': 'new.sftlyr.ws',
            'notes': 'random notes',
        }

        self.cci.edit(100, **args)
        service.editObject.assert_called_once_with(args, id=100)
    def execute(self, args):
        update_with_template_args(args)
        cci = CCIManager(self.client)
        self._update_with_like_args(args)

        # 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(',')

        # SSH keys may be a comma-separated list. Let's make it a real list.
        if isinstance(args.get('--key'), str):
            args['--key'] = args.get('--key').split(',')

        self._validate_args(args)

        # Do not create CCI with --test or --export
        do_create = not (args['--export'] or args['--test'])

        t = Table(['Item', 'cost'])
        t.align['Item'] = 'r'
        t.align['cost'] = 'r'
        data = self._parse_create_args(args)

        output = []
        if args.get('--test'):
            result = cci.verify_create_instance(**data)
            total_monthly = 0.0
            total_hourly = 0.0

            t = Table(['Item', 'cost'])
            t.align['Item'] = 'r'
            t.align['cost'] = 'r'

            for price in result['prices']:
                total_monthly += float(price.get('recurringFee', 0.0))
                total_hourly += float(price.get('hourlyRecurringFee', 0.0))
                if args.get('--hourly'):
                    rate = "%.2f" % float(price['hourlyRecurringFee'])
                else:
                    rate = "%.2f" % float(price['recurringFee'])

                t.add_row([price['item']['description'], rate])

            if args.get('--hourly'):
                total = total_hourly
            else:
                total = total_monthly

            billing_rate = 'monthly'
            if args.get('--hourly'):
                billing_rate = 'hourly'
            t.add_row(['Total %s cost' % billing_rate, "%.2f" % total])
            output.append(t)
            output.append(FormattedItem(
                None,
                ' -- ! Prices reflected here are retail and do not '
                'take account level discounts and are not guaranteed.')
            )

        if args['--export']:
            export_file = args.pop('--export')
            export_to_template(export_file, args, exclude=['--wait', '--test'])
            return 'Successfully exported options to a template file.'

        if do_create:
            if args['--really'] or confirm(
                    "This action will incur charges on your account. "
                    "Continue?"):
                result = cci.create_instance(**data)

                t = KeyValueTable(['name', 'value'])
                t.align['name'] = 'r'
                t.align['value'] = 'l'
                t.add_row(['id', result['id']])
                t.add_row(['created', result['createDate']])
                t.add_row(['guid', result['globalIdentifier']])
                output.append(t)

                if args.get('--wait'):
                    ready = cci.wait_for_transaction(
                        result['id'], int(args.get('--wait') or 1))
                    t.add_row(['ready', ready])
            else:
                raise CLIAbort('Aborting CCI order.')

        return output
Example #7
0
    def on_post(self, req, resp, tenant_id, instance_id):
        body = json.loads(req.stream.read().decode())

        if len(body) == 0:
            return bad_request(resp, message="Malformed request body")

        vg_client = req.env["sl_client"]["Virtual_Guest"]
        cci = CCIManager(req.env["sl_client"])

        try:
            instance_id = int(instance_id)
        except ValueError:
            return not_found(resp, "Invalid instance ID specified.")

        instance = cci.get_instance(instance_id)

        if "pause" in body or "suspend" in body:
            try:
                vg_client.pause(id=instance_id)
            except SoftLayerAPIError as e:
                if "Unable to pause instance" in e.faultString:
                    return duplicate(resp, e.faultString)
                raise
            resp.status = 202
            return
        elif "unpause" in body or "resume" in body:
            vg_client.resume(id=instance_id)
            resp.status = 202
            return
        elif "reboot" in body:
            if body["reboot"].get("type") == "SOFT":
                vg_client.rebootSoft(id=instance_id)
            elif body["reboot"].get("type") == "HARD":
                vg_client.rebootHard(id=instance_id)
            else:
                vg_client.rebootDefault(id=instance_id)
            resp.status = 202
            return
        elif "os-stop" in body:
            vg_client.powerOff(id=instance_id)
            resp.status = 202
            return
        elif "os-start" in body:
            vg_client.powerOn(id=instance_id)
            resp.status = 202
            return
        elif "createImage" in body:
            image_name = body["createImage"]["name"]
            disks = []

            for disk in filter(lambda x: x["device"] == "0", instance["blockDevices"]):
                disks.append(disk)

            try:
                vg_client.createArchiveTransaction(
                    image_name, disks, "Auto-created by OpenStack compatibility layer", id=instance_id
                )
                # Workaround for not having an image guid until the image is
                # fully created. TODO: Fix this
                cci.wait_for_transaction(instance_id, 300)
                _filter = {
                    "privateBlockDeviceTemplateGroups": {
                        "name": {"operation": image_name},
                        "createDate": {"operation": "orderBy", "options": [{"name": "sort", "value": ["DESC"]}]},
                    }
                }

                acct = req.env["sl_client"]["Account"]
                matching_image = acct.getPrivateBlockDeviceTemplateGroups(
                    mask="id, globalIdentifier", filter=_filter, limit=1
                )
                image_guid = matching_image.get("globalIdentifier")

                url = self.app.get_endpoint_url("image", req, "v2_image", image_guid=image_guid)

                resp.status = 202
                resp.set_header("location", url)
            except SoftLayerAPIError as e:
                compute_fault(resp, e.faultString)
            return
        elif "os-getConsoleOutput" in body:
            resp.status = 501
            return

        return bad_request(resp, message="There is no such action: %s" % list(body.keys()), code=400)