예제 #1
0
    def configure(self, worker_context, failure_state=RESTART, attempts=None):
        self.log.debug('Begin router config')
        self.state = UP
        attempts = attempts or cfg.CONF.max_retries

        # FIXME: This might raise an error, which doesn't mean the
        # *router* is broken, but does mean we can't update it.
        # Change the exception to something the caller can catch
        # safely.
        self._ensure_cache(worker_context)
        if self.state == GONE:
            return

        addr = _get_management_address(self.router_obj)

        # FIXME: This should raise an explicit exception so the caller
        # knows that we could not talk to the router (versus the issue
        # above).
        interfaces = router_api.get_interfaces(
            addr, cfg.CONF.akanda_mgt_service_port)

        if not self._verify_interfaces(self.router_obj, interfaces):
            # FIXME: Need a REPLUG state when we support hot-plugging
            # interfaces.
            self.log.debug("Interfaces aren't plugged as expected.")
            self.state = REPLUG
            return

        # FIXME: Need to catch errors talking to neutron here.
        config = configuration.build_config(worker_context.neutron,
                                            self.router_obj, interfaces)
        self.log.debug('preparing to update config to %r', config)

        for i in xrange(attempts):
            try:
                router_api.update_config(addr,
                                         cfg.CONF.akanda_mgt_service_port,
                                         config)
            except Exception:
                if i == attempts - 1:
                    # Only log the traceback if we encounter it many times.
                    self.log.exception('failed to update config')
                else:
                    self.log.debug('failed to update config, attempt %d', i)
                time.sleep(cfg.CONF.retry_delay)
            else:
                self.state = CONFIGURED
                self.log.info('Router config updated')
                return
        else:
            # FIXME: We failed to configure the router too many times,
            # so restart it.
            self.state = failure_state
예제 #2
0
    def update_config(self, management_address, config):
        """Updates appliance configuration

        This is responsible for pushing configuration to the managed
        appliance
        """
        self.log.info(_('Updating config for %s'), self.name)
        start_time = timeutils.utcnow()
        akanda_client.update_config(management_address, self.mgt_port, config)
        delta = timeutils.delta_seconds(start_time, timeutils.utcnow())
        self.log.info(_('Config updated for %s after %s seconds'), self.name,
                      round(delta, 2))
예제 #3
0
    def update_config(self, management_address, config):
        """Updates appliance configuration

        This is responsible for pushing configuration to the managed
        appliance
        """
        self.log.info(_('Updating config for %s'), self.name)
        start_time = timeutils.utcnow()
        akanda_client.update_config(
            management_address, self.mgt_port, config)
        delta = timeutils.delta_seconds(start_time, timeutils.utcnow())
        self.log.info(_('Config updated for %s after %s seconds'),
                      self.name, round(delta, 2))
예제 #4
0
    def test_update_config_failure(self):
        config = {'foo': 'bar'}

        self.mock_put.return_value.status_code = 500
        self.mock_put.return_value.text = 'error_text'

        with self.assertRaises(Exception):
            akanda_client.update_config('fe80::2', 5000, config)

        self.mock_put.assert_called_once_with(
            'http://[fe80::2]:5000/v1/system/config',
            data='{"foo": "bar"}',
            headers={'Content-type': 'application/json'},
            timeout=90)
예제 #5
0
    def configure(self, worker_context, failure_state=RESTART, attempts=None):
        self.log.debug("Begin router config")
        self.state = UP
        attempts = attempts or cfg.CONF.max_retries

        # FIXME: This might raise an error, which doesn't mean the
        # *router* is broken, but does mean we can't update it.
        # Change the exception to something the caller can catch
        # safely.
        self._ensure_cache(worker_context)
        if self.state == GONE:
            return

        addr = _get_management_address(self.router_obj)

        # FIXME: This should raise an explicit exception so the caller
        # knows that we could not talk to the router (versus the issue
        # above).
        interfaces = router_api.get_interfaces(addr, cfg.CONF.akanda_mgt_service_port)

        if not self._verify_interfaces(self.router_obj, interfaces):
            # FIXME: Need a REPLUG state when we support hot-plugging
            # interfaces.
            self.log.debug("Interfaces aren't plugged as expected.")
            self.state = REPLUG
            return

        # FIXME: Need to catch errors talking to neutron here.
        config = configuration.build_config(worker_context.neutron, self.router_obj, interfaces)
        self.log.debug("preparing to update config to %r", config)

        for i in xrange(attempts):
            try:
                router_api.update_config(addr, cfg.CONF.akanda_mgt_service_port, config)
            except Exception:
                if i == attempts - 1:
                    # Only log the traceback if we encounter it many times.
                    self.log.exception("failed to update config")
                else:
                    self.log.debug("failed to update config, attempt %d", i)
                time.sleep(cfg.CONF.retry_delay)
            else:
                self.state = CONFIGURED
                self.log.info("Router config updated")
                return
        else:
            # FIXME: We failed to configure the router too many times,
            # so restart it.
            self.state = failure_state
예제 #6
0
    def test_update_config_failure(self):
        config = {"foo": "bar"}

        self.mock_put.return_value.status_code = 500
        self.mock_put.return_value.text = "error_text"

        with self.assertRaises(Exception):
            akanda_client.update_config("fe80::2", 5000, config)

        self.mock_put.assert_called_once_with(
            "http://[fe80::2]:5000/v1/system/config",
            data='{"foo": "bar"}',
            headers={"Content-type": "application/json"},
            timeout=90,
        )
예제 #7
0
    def test_update_config_failure(self):
        config = {'foo': 'bar'}

        self.mock_put.return_value.status_code = 500
        self.mock_put.return_value.text = 'error_text'

        with self.assertRaises(Exception):
            akanda_client.update_config('fe80::2', 5000, config)

        self.mock_put.assert_called_once_with(
            'http://[fe80::2]:5000/v1/system/config',
            data='{"foo": "bar"}',
            headers={'Content-type': 'application/json'},
            timeout=90
        )
예제 #8
0
    def test_update_config(self):
        config = {'foo': 'bar'}
        self.mock_put.return_value.status_code = 200
        self.mock_put.return_value.json.return_value = config

        resp = akanda_client.update_config('fe80::2', 5000, config)

        self.mock_put.assert_called_once_with(
            'http://[fe80::2]:5000/v1/system/config',
            data='{"foo": "bar"}',
            headers={'Content-type': 'application/json'},
            timeout=90)
        self.assertEqual(resp, config)
예제 #9
0
    def test_update_config(self):
        config = {'foo': 'bar'}
        self.mock_put.return_value.status_code = 200
        self.mock_put.return_value.json.return_value = config

        resp = akanda_client.update_config('fe80::2', 5000, config)

        self.mock_put.assert_called_once_with(
            'http://[fe80::2]:5000/v1/system/config',
            data='{"foo": "bar"}',
            headers={'Content-type': 'application/json'},
            timeout=90)
        self.assertEqual(resp, config)
예제 #10
0
    def test_update_config(self):
        config = {"foo": "bar"}
        self.mock_put.return_value.status_code = 200
        self.mock_put.return_value.json.return_value = config

        resp = akanda_client.update_config("fe80::2", 5000, config)

        self.mock_put.assert_called_once_with(
            "http://[fe80::2]:5000/v1/system/config",
            data='{"foo": "bar"}',
            headers={"Content-type": "application/json"},
            timeout=90,
        )
        self.assertEqual(resp, config)
예제 #11
0
    def test_update_config_with_custom_config(self):
        config = {"foo": "bar"}
        self.mock_put.return_value.status_code = 200
        self.mock_put.return_value.json.return_value = config

        with mock.patch.object(akanda_client.cfg, "CONF") as cfg:
            cfg.config_timeout = 5
            resp = akanda_client.update_config("fe80::2", 5000, config)

            self.mock_put.assert_called_once_with(
                "http://[fe80::2]:5000/v1/system/config",
                data='{"foo": "bar"}',
                headers={"Content-type": "application/json"},
                timeout=5,
            )
            self.assertEqual(resp, config)
예제 #12
0
    def configure(self, worker_context, failure_state=RESTART, attempts=None):
        self.log.debug("Begin router config")
        self.state = UP
        attempts = attempts or cfg.CONF.max_retries

        # FIXME: This might raise an error, which doesn't mean the
        # *router* is broken, but does mean we can't update it.
        # Change the exception to something the caller can catch
        # safely.
        self._ensure_cache(worker_context)
        if self.state == GONE:
            return

        # FIXME: This should raise an explicit exception so the caller

        # knows that we could not talk to the router (versus the issue
        # above).
        interfaces = router_api.get_interfaces(self.instance_info.management_address, cfg.CONF.akanda_mgt_service_port)

        if not self._verify_interfaces(self.router_obj, interfaces):
            # FIXME: Need a REPLUG state when we support hot-plugging
            # interfaces.
            self.log.debug("Interfaces aren't plugged as expected.")
            self.state = REPLUG
            return

        # TODO(mark): We're in the first phase of VRRP, so we need
        # map the interface to the network ID.
        # Eventually we'll send VRRP data and real interface data
        port_mac_to_net = {p.mac_address: p.network_id for p in self.instance_info.ports}
        # Add in the management port
        mgt_port = self.instance_info.management_port
        port_mac_to_net[mgt_port.mac_address] = mgt_port.network_id

        # this is a network to logical interface id
        iface_map = {port_mac_to_net[i["lladdr"]]: i["ifname"] for i in interfaces if i["lladdr"] in port_mac_to_net}

        # FIXME: Need to catch errors talking to neutron here.
        config = configuration.build_config(worker_context.neutron, self.router_obj, mgt_port, iface_map)
        self.log.debug("preparing to update config to %r", config)

        for i in xrange(attempts):
            try:
                router_api.update_config(
                    self.instance_info.management_address, cfg.CONF.akanda_mgt_service_port, config
                )
            except Exception:
                if i == attempts - 1:
                    # Only log the traceback if we encounter it many times.
                    self.log.exception(_LE("Failed to update config"))
                else:
                    self.log.debug("failed to update config, attempt %d", i)
                time.sleep(cfg.CONF.retry_delay)
            else:
                self.state = CONFIGURED
                self.log.info(_LI("Router config updated"))
                return
        else:
            # FIXME: We failed to configure the router too many times,
            # so restart it.
            self.state = failure_state