def _schedule_bigiq_agent(self, context, loadbalancer_id, active=True):
     # TODO: agent scheduler
     query = context.session.query(agents_db.Agent)
     query = query.filter_by(agent_type=constants.LBAASV2_BIGIQ_AGENT_TYPE,
                             admin_state_up=active)
     agents = [agent for agent in query]
     if len(agents) > 0:
         # Bind loadbalancer with agent
         binding = agent_scheduler.LoadbalancerAgentBinding()
         binding.agent = agents[0]
         binding.loadbalancer_id = loadbalancer_id
         context.session.add(binding)
         return agents[0]
     else:
         raise exceptions.NoEligibleBIGIQAgent(
             loadbalancer_id=loadbalancer_id
         )
Exemplo n.º 2
0
    def schedule(self, plugin, context, loadbalancer_id, env=None):
        """Schedule the loadbalancer to an active loadbalancer agent.

        If there is no enabled agent hosting it.
        """

        with context.session.begin(subtransactions=True):
            loadbalancer = plugin.db.get_loadbalancer(context, loadbalancer_id)
            # If the loadbalancer is hosted on an active agent
            # already, return that agent or one in its env
            lbaas_agent = self.get_lbaas_agent_hosting_loadbalancer(
                plugin,
                context,
                loadbalancer.id,
                env
            )

            if lbaas_agent:
                lbaas_agent = lbaas_agent['agent']
                LOG.debug(' Assigning task to agent %s.'
                          % (lbaas_agent['id']))
                return lbaas_agent

            # There is no existing loadbalancer agent binding.
            # Find all active agent candidates in this env.
            # We use environment_prefix to find F5® agents
            # rather then map to the agent binary name.
            candidates = self.get_agents_in_env(
                context,
                plugin,
                env,
                active=True
            )

            LOG.debug("candidate agents: %s", candidates)
            if len(candidates) == 0:
                LOG.error('No f5 lbaas agents are active for env %s' % env)
                raise lbaas_agentschedulerv2.NoActiveLbaasAgent(
                    loadbalancer_id=loadbalancer.id)

            # We have active candidates to choose from.
            # Qualify them by tenant affinity and then capacity.
            chosen_agent = None
            agents_by_group = defaultdict(list)
            capacity_by_group = {}

            for candidate in candidates:
                # Organize agents by their environment group
                # and collect each group's max capacity.
                ac = self.deserialize_agent_configurations(
                    candidate['configurations']
                )
                gn = 1
                if 'environment_group_number' in ac:
                    gn = ac['environment_group_number']
                agents_by_group[gn].append(candidate)

                # populate each group's capacity
                group_capacity = self.get_capacity(ac)
                if gn not in capacity_by_group:
                    capacity_by_group[gn] = group_capacity
                else:
                    if group_capacity > capacity_by_group[gn]:
                        capacity_by_group[gn] = group_capacity

                # Do we already have this tenant assigned to this
                # agent candidate? If we do and it has capacity
                # then assign this loadbalancer to this agent.
                assigned_lbs = plugin.db.list_loadbalancers_on_lbaas_agent(
                    context, candidate['id'])
                for assigned_lb in assigned_lbs:
                    if loadbalancer.tenant_id == assigned_lb.tenant_id:
                        chosen_agent = candidate
                        break

                if chosen_agent:
                    # Does the agent which had tenants assigned
                    # to it still have capacity?
                    if group_capacity >= 1.0:
                        chosen_agent = None
                    else:
                        break

            # If we don't have an agent with capacity associated
            # with our tenant_id, let's pick an agent based on
            # the group with the lowest capacity score.
            if not chosen_agent:
                # lets get an agent from the group with the
                # lowest capacity score
                lowest_utilization = 1.0
                selected_group = 1
                for group, capacity in capacity_by_group.items():
                    if capacity < lowest_utilization:
                        lowest_utilization = capacity
                        selected_group = group

                LOG.debug('%s group %s scheduled with capacity %s'
                          % (env, selected_group, lowest_utilization))
                if lowest_utilization < 1.0:
                    # Choose a agent in the env group for this
                    # tenant at random.
                    chosen_agent = random.choice(
                        agents_by_group[selected_group]
                    )

            # If there are no agents with available capacity, raise exception
            if not chosen_agent:
                LOG.warn('No capacity left on any agents in env: %s' % env)
                LOG.warn('Group capacity in environment %s were %s.'
                         % (env, capacity_by_group))
                raise lbaas_agentschedulerv2.NoEligibleLbaasAgent(
                    loadbalancer_id=loadbalancer.id)

            binding = agent_scheduler.LoadbalancerAgentBinding()
            binding.agent = chosen_agent
            binding.loadbalancer_id = loadbalancer.id
            context.session.add(binding)

            LOG.debug(('Loadbalancer %(loadbalancer_id)s is scheduled to '
                       'lbaas agent %(agent_id)s'),
                      {'loadbalancer_id': loadbalancer.id,
                       'agent_id': chosen_agent['id']})

            return chosen_agent