瀏覽代碼

FD3-809 multiple status in subnet

Guillermo Espinoza 6 年之前
父節點
當前提交
6625b06d95

+ 8 - 1
src/HostBundle/Resources/views/translate_status.html.twig

@@ -2,7 +2,14 @@
 
 {% block field %}
 
-{{ value | trans({}, 'WorkflowLabel') }}
+{% set status = value|split(',') %}
+{% if status is iterable %}
+    {% for st in status %}
+        {{ st | trans({}, 'WorkflowLabel') }}<br />
+    {% endfor %}
+{% else %}
+    {{ value | trans({}, 'WorkflowLabel') }}
+{% endif %}
 
 {% endblock %}
 

+ 27 - 7
src/IPv4Bundle/Admin/SubNetAdmin.php

@@ -3,12 +3,12 @@
 namespace IPv4Bundle\Admin;
 
 use Base\AdminBundle\Admin\BaseAdmin;
+use HostBundle\Utils\HostStatus;
 use Sonata\AdminBundle\Datagrid\DatagridMapper;
 use Sonata\AdminBundle\Datagrid\ListMapper;
 use Sonata\AdminBundle\Form\FormMapper;
 use Sonata\AdminBundle\Show\ShowMapper;
 use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
-use HostBundle\Utils\HostStatus;
 
 class SubNetAdmin extends BaseAdmin
 {
@@ -20,9 +20,23 @@ class SubNetAdmin extends BaseAdmin
         $datagridMapper
             ->add('address')
             ->add('allowedHostType')
-            ->add('status', 'doctrine_orm_choice', [], 'choice', [
-                'choices' => HostStatus::getChoices(),
-                'translation_domain' => 'WorkflowLabel',
+            ->add('status', 'doctrine_orm_callback', [
+                'callback' => function($queryBuilder, $alias, $field, $value) {
+                    if (!$value['value']) {
+                        return;
+                    }
+
+                    $queryBuilder
+                        ->andWhere("{$alias}.status LIKE :status")
+                        ->setParameter('status', "%{$value['value']}%");
+
+                    return true;
+                },
+                'field_type' => ChoiceType::class,
+                'field_options' => [
+                    'choices' => HostStatus::getChoices(),
+                    'translation_domain' => 'WorkflowLabel',
+                ],
             ])
         ;
     }
@@ -39,7 +53,8 @@ class SubNetAdmin extends BaseAdmin
                 'template' => 'HostBundle:CRUD:dhcp_options.html.twig',
             ])
             ->add('allowedHostType')
-            ->add('status', null, [
+            ->add('statusString', null, [
+                'label' => 'list.label_status',
                 'template' => 'HostBundle::translate_status.html.twig',
             ])
             ->add('netGroup')
@@ -78,6 +93,7 @@ class SubNetAdmin extends BaseAdmin
                 ->add('status', ChoiceType::class, [
                     'choices' => HostStatus::getChoices(),
                     'translation_domain' => 'WorkflowLabel',
+                    'multiple' => true,
                 ])
                 ->add('netGroup')
             ->end()
@@ -102,13 +118,17 @@ class SubNetAdmin extends BaseAdmin
         ;
     }
 
-    function prePersist($object){
+    function prePersist($object)
+    {
         $object->setOptions(json_encode($object->getDHCPOption()));
+
         return parent::preUpdate($object);
     }
 
-    function preUpdate($object){
+    function preUpdate($object)
+    {
         $object->setOptions(json_encode($object->getDHCPOption()));
+        
         return parent::preUpdate($object);
     }
 }

+ 20 - 6
src/IPv4Bundle/Entity/SubNet.php

@@ -16,7 +16,7 @@ use WorkflowBundle\Entity\Interfaces\WorkflowInterface;
 use WorkflowBundle\Entity\Traits\WorkflowTrait;
 
 /**
- * @ORM\Entity
+ * @ORM\Entity(repositoryClass="IPv4Bundle\Repository\SubNetRepository")
  *
  * @UniqueEntity("address")
  *
@@ -96,11 +96,17 @@ class SubNet implements TenancyIdTraitInterface, WorkflowInterface
     protected $currentState = null;
 
     /**
-     * @ORM\Column(type="string")
+     * @ORM\Column(type="array")
      * 
-     * @Assert\NotBlank
+     * @Assert\All({
+     *     @Assert\NotBlank
+     * })
+     * @Assert\Count(
+     *      min = 1,
+     *      minMessage = "You must specify at least one status"
+     * )
      */
-    protected $status = \HostBundle\Utils\HostStatus::STATE_ACTIVE;
+    protected $status = [ \HostBundle\Utils\HostStatus::STATE_ACTIVE ];
 
 
     public function __construct()
@@ -263,7 +269,7 @@ class SubNet implements TenancyIdTraitInterface, WorkflowInterface
     }
 
     /**
-     * @param string $status
+     * @param array $status
      *
      * @return SubNet
      */
@@ -275,13 +281,21 @@ class SubNet implements TenancyIdTraitInterface, WorkflowInterface
     }
 
     /**
-     * @return string
+     * @return array
      */
     public function getStatus()
     {
         return $this->status;
     }
 
+    /**
+     * @return string
+     */
+    public function getStatusString()
+    {
+        return implode(',', array_values($this->status));
+    }
+
     /**
     * @param ExecutionContextInterface $context
     */

+ 11 - 8
src/IPv4Bundle/EventListener/SubnetStatusOrHostTypeChangeSubscriber.php

@@ -31,7 +31,7 @@ class SubnetStatusOrHostTypeChangeSubscriber implements EventSubscriber
     public function getSubscribedEvents()
     {
         return array(
-            'preUpdate',
+            'postUpdate',
             'preRemove',
         );
     }
@@ -39,7 +39,7 @@ class SubnetStatusOrHostTypeChangeSubscriber implements EventSubscriber
     /**
      * @param LifecycleEventArgs $args
      */
-    public function preUpdate(LifecycleEventArgs $args)
+    public function postUpdate(LifecycleEventArgs $args)
     {
         $this->execute($args);
     }
@@ -67,6 +67,7 @@ class SubnetStatusOrHostTypeChangeSubscriber implements EventSubscriber
             $uow->computeChangeSets();
             $entity = $args->getEntity();
             $changeset = $uow->getEntityChangeSet($entity);
+            
             if ($entity instanceof SubNet && (isset($changeset['status']) || isset($changeset['allowedHostType']))) {
                 // setting fixed address to null to all hosts in the pools static associated to the subnet
                 $ipRange = $this->serviceContainer->get('pool_ipv4_service')->getStaticPoolIPRangeBySubnet($entity);
@@ -80,12 +81,14 @@ class SubnetStatusOrHostTypeChangeSubscriber implements EventSubscriber
                     }
                 }
                 foreach ($hosts as $host) {
-                    $host->setFixedAddress(null);
-                    $host->setIpv4Address(null);
-                    $host->setFixedIP(false);
-
-                    $em->persist($host);
-                    $em->flush($host);
+                    if (!in_array($host->getState(), $entity->getStatus())) {
+                        $host->setFixedAddress(null);
+                        $host->setIpv4Address(null);
+                        $host->setFixedIP(false);
+    
+                        // $em->persist($host);
+                        $em->flush($host);
+                    }
                 }
             }
         } catch (\Exception $ex) {

+ 1 - 1
src/IPv4Bundle/Repository/PoolRepository.php

@@ -43,7 +43,7 @@ class PoolRepository extends \Doctrine\ORM\EntityRepository
             $qb->join('Pool.subNet', 'Subnet')
                ->join('Subnet.allowedHostType', 'HostType')
                ->andWhere('HostType.id = :id')->setParameter('id', $hostType->getId())
-               ->andWhere('Subnet.status = :status')->setParameter('status', $status)
+               ->andWhere('Subnet.status LIKE :status')->setParameter('status', "%{$status}%")
                ;
         }
         

+ 52 - 0
src/IPv4Bundle/Repository/SubNetRepository.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace IPv4Bundle\Repository;
+
+use IPv4Bundle\Entity\SubNet;
+use Doctrine\ORM\Query;
+
+class SubNetRepository extends \Doctrine\ORM\EntityRepository
+{
+
+    /**
+     * @return array
+     */
+    public function findSharedNetworks()
+    {
+        $sql = 'SELECT s.id
+            FROM sub_net s 
+            JOIN net_group n ON net_group_id = n.id
+            JOIN host_type h ON allowed_host_type_id = h.id
+            WHERE (allowed_host_type_id, net_group_id, status) IN ( 
+                SELECT allowed_host_type_id, net_group_id , status 
+                FROM sub_net 
+                GROUP BY allowed_host_type_id, net_group_id, status 
+                HAVING COUNT(*) > 1)
+            ORDER BY allowed_host_type_id, net_group_id, status';
+        $stmt = $this->getEntityManager()->getConnection()->prepare($sql);
+        $stmt->execute();
+
+        return $stmt->fetchAll();
+    }
+
+    /**
+     * @param array $ids
+     * 
+     * @return array
+     */
+    public function findAllNotIn($ids)
+    {
+        $qb = $this->createQueryBuilder('SubNet');
+        $qb->select(array('SubNet'))
+                ->where(
+                    $qb->expr()->notIn(
+                        'SubNet.id',
+                        ':ids'
+                    )
+                )
+                ->setParameter('ids', implode(',', $ids));
+
+        return $qb->getQuery()->getResult();
+    }
+
+}

+ 141 - 7
src/KeaBundle/Services/BaseKea.php

@@ -8,6 +8,11 @@ use KeaBundle\Interfaces\KeaConfigInterface;
 class BaseKea implements KeaConfigInterface
 {
 
+    /**
+     * @var array
+     */
+    private $shared_networks = [];
+
     /**
      * @var array
      */
@@ -72,6 +77,11 @@ class BaseKea implements KeaConfigInterface
      */
     public function getConfig($data = array(), $logging = false)
     {
+        $this->classes = [];
+        if (isset($data['shared-networks'])) {
+            $this->sharedNetworksConfig($data['shared-networks'], $data['reservations']);
+        }
+
         if (isset($data['subnets'])) {
             $this->subnetConfig($data['subnets'], $data['reservations']);
         }
@@ -90,6 +100,7 @@ class BaseKea implements KeaConfigInterface
                         'lease-database' => $this->leaseDatabaseConfig($data),
                         'hosts-database' => $this->leaseDatabaseConfig($data),
                         'client-classes' => $this->client_classes,
+                        'shared-networks' => $this->shared_networks,
                         'subnet4' => $this->subnet4,
                         'hooks-libraries' => $this->hooks_libraries,
                         'interfaces-config' => $this->getInterfacesConfig(),
@@ -98,13 +109,137 @@ class BaseKea implements KeaConfigInterface
             ))], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
     }
 
+    /**
+     * @param array $subnets
+     */
+    private function sharedNetworksConfig($subnets, $reservations)
+    {
+        $sharedNetwork = [
+            'name' => 'shared-network-',
+            'option-data' => [],
+            'subnet4' => [],
+        ];
+        $hostType = $netGroup = $status = null;
+        if (isset($subnets[0])) {
+            $hostType = $subnets[0]->getAllowedHostType();
+            $netGroup = $subnets[0]->getNetGroup();
+            $status = $subnets[0]->getStatus();
+            $sharedNetworkTmp = $sharedNetwork;
+            $sharedNetworkTmp['name'] = $sharedNetworkTmp['name'] . 1;
+            $sharedNetworkTmp['relay'] = $this->getOptionDataSharedNetwork($subnets[0]);
+            $sharedNetworkTmp['subnet4'][] = $this->getSubnetSharedNetwork($subnets[0], $reservations);
+            unset($subnets[0]);
+        }
+        foreach ($subnets as $subnet) {
+            if ($subnet->getAllowedHostType() != $hostType && 
+                $subnet->getNetGroup() != $netGroup && 
+                $subnet->getStatus() != $status) {
+
+                $this->shared_networks[] = $sharedNetworkTmp;
+
+                $hostType = $subnet->getAllowedHostType();
+                $netGroup = $subnet->getNetGroup();
+                $status = $subnet->getStatus();
+
+                $sharedNetworkTmp = $sharedNetwork;
+                $sharedNetworkTmp['name'] = $sharedNetworkTmp['name'] . count($this->shared_networks) + 1;
+                $sharedNetworkTmp['relay'] = $this->getOptionDataSharedNetwork($subnet);
+            }
+            $sharedNetworkTmp['subnet4'][] = $this->getSubnetSharedNetwork($subnet, $reservations);
+        }
+        $this->shared_networks[] = $sharedNetworkTmp;
+    }
+
+    /**
+     * @param SubNet $subnet
+     * 
+     * @return array
+     */
+    private function getOptionDataSharedNetwork($subnet)
+    {
+        $netgroup = $subnet->getNetGroup();
+        if ($netgroup && count($netgroup->getRelay())) {
+            $relay = [];
+            foreach ($netgroup->getRelay() as $ip) {
+                $relay[] = $ip;
+            }
+            return [
+                    'ip-addresses' => $relay,
+                ];
+        }
+
+        return [];
+    }
+
+    /**
+     * @param SubNet $subnet
+     * 
+     * @return array
+     */
+    private function getSubnetSharedNetwork($subnet, $reservations)
+    {
+        $pools = [];
+        foreach ($subnet->getIpPool() as $pool) {
+            // only add non static pools
+            if ($pool->getIsStatic() == false) {
+                $pools[] = [
+                    'pool' => $pool->getFirstIp() . ' - ' . $pool->getLastIp(),
+                ];
+            }
+        }
+
+        $hostType = $subnet->getAllowedHostType();
+        $client_class = 'cm';
+        if ($hostType != 'Cablemodem') {
+            $client_class = $hostType->getShortname();
+        }
+
+        foreach ($subnet->getStatus() as $status) {
+            if ($status != HostStatus::STATE_NONE) {
+                $client_class .= '-' . $status;
+            }
+        }
+
+        $subnetConf = [
+            'subnet' => $subnet->getAddress(),
+            'pools' => $pools,
+        ];
+
+        if(isset($reservations[$subnet->getId()])) {
+            $subnetConf['reservations'] = $reservations[$subnet->getId()];
+        }
+
+        $nextServer = $subnet->getNextServer();
+        if ($nextServer != '') {
+            $subnetConf['next-server'] = $nextServer;
+        }
+
+        $filename = $subnet->getFilename();
+        if ($filename != '') {
+            $subnetConf['boot-file-name'] = $filename;
+        }
+
+        if ($client_class != '') {
+            $subnetConf['client-class'] = $client_class;
+            if (!in_array($client_class, $this->classes)) {
+                $this->classes[] = $client_class;
+                $this->client_classes[] = [
+                    'name' => $client_class,
+                ];
+            }
+        }
+        
+        $this->setOptionData($subnet, $subnetConf);
+
+        return $subnetConf;
+    }
+
     /**
      * @param array $subnets
      * @param array $reservations
      */
     private function subnetConfig($subnets, $reservations)
     {
-        $classes = [];
         foreach ($subnets as $subnet) {
             $pools = [];
             foreach ($subnet->getIpPool() as $pool) {
@@ -122,11 +257,10 @@ class BaseKea implements KeaConfigInterface
                 $client_class = $hostType->getShortname();
             }
 
-            if ($subnet->getStatus() != HostStatus::STATE_NONE && $subnet->getStatus() != '') {
-                if ($client_class != '') {
-                    $client_class .= '-';
+            foreach ($subnet->getStatus() as $status) {
+                if ($status != HostStatus::STATE_NONE) {
+                    $client_class .= '-' . $status;
                 }
-                $client_class .= $subnet->getStatus();
             }
 
             $subnetConf = [
@@ -150,8 +284,8 @@ class BaseKea implements KeaConfigInterface
 
             if ($client_class != '') {
                 $subnetConf['client-class'] = $client_class;
-                if (!in_array($client_class, $classes)) {
-                    $classes[] = $client_class;
+                if (!in_array($client_class, $this->classes)) {
+                    $this->classes[] = $client_class;
                     $this->client_classes[] = [
                         'name' => $client_class,
                     ];

+ 7 - 1
src/KeaBundle/Services/KeaConfigService.php

@@ -82,10 +82,16 @@ class KeaConfigService
         if (class_exists($fullClass)) {
             $keaConfig = new $fullClass;
             if ($keaConfig instanceof KeaConfigInterface) {
+                $sharedNetworks = $this->subnetRepository->findSharedNetworks();
+                $sharedNetworksIds = array_map(function($subnet) { return $subnet['id']; }, $sharedNetworks);
+                $subnetRepository = $this->subnetRepository;
+                $sharedNetworks = array_map(function($subnet) use ($subnetRepository) { return $subnetRepository->find($subnet['id']); }, $sharedNetworks);
+
                 $data = [
                     'dhcp' => $id ? $this->dhcpRepository->find($id) : null,
                     'hosts' => $this->hostRepository->findAll(),
-                    'subnets' => $this->subnetRepository->findAll(),
+                    'shared-networks' => $sharedNetworks,
+                    'subnets' => $this->subnetRepository->findAllNotIn($sharedNetworksIds),
                     'reservations' => $this->getHostsReservations(),
                     'library' => $library,
                     'db' => $this->databaseConfig,