瀏覽代碼

Merge branch 'master' of bitbucket.org:ikflowdat/dhcp into FD2-607

Luciano Andrade 7 年之前
父節點
當前提交
8271086cef

+ 1 - 3
app/Resources/workflows/workflow_list.yml.dist

@@ -7,11 +7,9 @@ framework:
         arguments:
           - currentState
       supports:
-        - HostBundle\Entity\Host
+        - IPv4Bundle\Entity\Host
         - IPv4Bundle\Entity\Pool
         - IPv4Bundle\Entity\SubNet
-        - IPv6Bundle\Entity\Pool
-        - IPv6Bundle\Entity\SubNet
       initial_place: active
       places:
         - active

+ 5 - 0
app/config/roles.yml

@@ -72,6 +72,11 @@ security:
         ROLE_SONATA_KEA_CONFIG_EDITOR: [ROLE_SONATA_KEA_CONFIG_READER, ROLE_SONATA_ADMIN_KEA_CONFIG_CREATE, ROLE_SONATA_ADMIN_KEA_CONFIG_EDIT]
         ROLE_SONATA_KEA_CONFIG_ADMIN: [ROLE_SONATA_KEA_CONFIG_EDITOR, ROLE_SONATA_ADMIN_KEA_CONFIG_DELETE, ROLE_SONATA_ADMIN_KEA_CONFIG_EXPORT]
 
+        # LEASE_4
+        ROLE_SONATA_LEASE_4_READER: [ROLE_ADMIN, ROLE_SONATA_ADMIN_LEASE_4_LIST, ROLE_SONATA_ADMIN_LEASE_4_VIEW]
+        ROLE_SONATA_LEASE_4_EDITOR: [ROLE_SONATA_LEASE_4_READER, ROLE_SONATA_ADMIN_LEASE_4_CREATE, ROLE_SONATA_ADMIN_LEASE_4_EDIT]
+        ROLE_SONATA_LEASE_4_ADMIN: [ROLE_SONATA_LEASE_4_EDITOR, ROLE_SONATA_ADMIN_LEASE_4_DELETE, ROLE_SONATA_ADMIN_LEASE_4_EXPORT]
+
         ROLE_ADMIN_TENANCIES: ROLE_ADMIN_TENANCIES
         ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN]
         ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_USER_CREATE, ROLE_ADMIN_TENANCIES, ROLE_ALLOWED_TO_SWITCH]

+ 10 - 10
composer.lock

@@ -1457,7 +1457,7 @@
             "source": {
                 "type": "git",
                 "url": "ssh://git@200.50.168.30:222/VendorSoftwareFlowdat3/BaseAdmin.git",
-                "reference": "40f690b7915e623069777fc919d332a3a0d7d6eb"
+                "reference": "97587f95769fcfac8f3c43fae36aa02633960f62"
             },
             "type": "library",
             "autoload": {
@@ -1472,7 +1472,7 @@
                 "bootstrap",
                 "sonata"
             ],
-            "time": "2018-06-21T11:53:57+00:00"
+            "time": "2018-07-04T17:03:04+00:00"
         },
         {
             "name": "ik/device-bundle",
@@ -1549,7 +1549,7 @@
             "source": {
                 "type": "git",
                 "url": "ssh://git@200.50.168.30:222/VendorSoftwareFlowdat3/BaseOAuthClientBundle.git",
-                "reference": "5d423246bfa5a40b05195f36316b57bbcd47be62"
+                "reference": "2373f6de17349f1c99a768c4c3a0803df2cc08ca"
             },
             "require": {
                 "ext-curl": "*",
@@ -1568,7 +1568,7 @@
                 "bundle",
                 "oauth"
             ],
-            "time": "2018-06-25T12:54:07+00:00"
+            "time": "2018-07-03T12:02:21+00:00"
         },
         {
             "name": "ik/owner-voter-bundle",
@@ -1599,7 +1599,7 @@
             "source": {
                 "type": "git",
                 "url": "ssh://git@200.50.168.30:222/VendorSoftwareFlowdat3/TemplateBundle.git",
-                "reference": "14e7b7c9d0deadf8c779874419cf2f183a02bbf8"
+                "reference": "7e50327475180f03fa24a2fa5ee1dc01dadd2bfa"
             },
             "require": {
                 "ik/base-admin-bundle": "*"
@@ -1617,7 +1617,7 @@
                 "bundle",
                 "template"
             ],
-            "time": "2018-04-24T15:29:11+00:00"
+            "time": "2018-07-04T14:44:27+00:00"
         },
         {
             "name": "ik/webservice-bundle",
@@ -1625,7 +1625,7 @@
             "source": {
                 "type": "git",
                 "url": "ssh://git@200.50.168.30:222/VendorSoftwareFlowdat3/Webservice.git",
-                "reference": "2051a376f191c1b72f3a8f2feb875dca03de77fc"
+                "reference": "4fb907804f45b182cda4c48551adf5240386111a"
             },
             "require": {
                 "ext-curl": "*",
@@ -1638,7 +1638,7 @@
                 }
             },
             "description": "The Flowdat3 Webservice Rest",
-            "time": "2018-06-07T18:40:05+00:00"
+            "time": "2018-07-03T12:59:44+00:00"
         },
         {
             "name": "ik/workflow-bundle",
@@ -1646,7 +1646,7 @@
             "source": {
                 "type": "git",
                 "url": "ssh://git@200.50.168.30:222/VendorSoftwareFlowdat3/WorkflowBundle.git",
-                "reference": "47ca3a59560cd1e7d8ae5e06ddbea62094fc2996"
+                "reference": "184c2d1c00423b71fd1eae098eead7b938de1882"
             },
             "require": {
                 "php-amqplib/rabbitmq-bundle": "^1.12"
@@ -1676,7 +1676,7 @@
                 "bundle",
                 "workflow"
             ],
-            "time": "2018-06-25T18:50:13+00:00"
+            "time": "2018-07-04T14:51:55+00:00"
         },
         {
             "name": "incenteev/composer-parameter-handler",

+ 53 - 5
src/HostBundle/Admin/HostAdmin.php

@@ -3,11 +3,14 @@
 namespace HostBundle\Admin;
 
 use Base\AdminBundle\Admin\BaseAdmin;
+use Doctrine\ORM\EntityRepository;
+use HostBundle\Entity\Host  ;
 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\Bridge\Doctrine\Form\Type\EntityType;
 use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
 
 class HostAdmin extends BaseAdmin
@@ -19,8 +22,24 @@ class HostAdmin extends BaseAdmin
     {
         $datagridMapper
             ->add('mac')
-            ->add('state')
-        ;
+            ->add('hostType')
+            ->add('state', 'doctrine_orm_choice', [], 'choice', [
+                'choices' => HostStatus::getChoices(),
+            ])
+            ->add('options', 'doctrine_orm_callback', [
+                'callback' => function($queryBuilder, $alias, $field, $value) {
+                    if (!$value['value']) {
+                        return;
+                    }
+
+                    $queryBuilder
+                        ->andWhere("{$alias}.options LIKE :fixed_address")
+                        ->setParameter('fixed_address', "%\"fixed_address\":\"{$value['value']}%");
+
+                    return true;
+                },
+                'label' => 'filter.label_options_fixed_address',
+            ]);
     }
 
     /**
@@ -32,6 +51,8 @@ class HostAdmin extends BaseAdmin
             ->add('mac')
             ->add('hostType')
             ->add('state')
+            ->add('options.fixed_address')
+            ->add('host')
             ->add('_action', null, array(
                 'actions' => array(
                     'show' => array(),
@@ -47,6 +68,8 @@ class HostAdmin extends BaseAdmin
      */
     protected function configureFormFields(FormMapper $formMapper)
     {
+        $subject = $this->getSubject();
+        
         $formMapper
             ->tab('Host')
             ->with('Host')
@@ -58,6 +81,23 @@ class HostAdmin extends BaseAdmin
                 'choices' => HostStatus::getChoices(),
                 'translation_domain' => 'HostBundle',
             ])
+            ->add('host', EntityType::class, [
+                'class' => Host::class,
+                'query_builder' => function (EntityRepository $er) use ($subject) {
+                    $qb = $er->createQueryBuilder('Host')
+                    ->join('Host.hostType', 'HostType')
+                    ->andWhere('HostType.name = \'Cablemodem\'')
+                    ->orderBy('Host.mac', 'ASC');
+                    
+                    $mac = $subject->getMac();
+                    if ($mac) {
+                        $qb->andWhere('Host.mac <> :mac')->setParameter('mac', $mac);
+                    }
+                    
+                    return $qb;
+                },
+                'required' => false,
+            ])
         ->end()
         ->end()
         ;
@@ -74,6 +114,7 @@ class HostAdmin extends BaseAdmin
             ->add('mac')
             ->add('hostType')
             ->add('state')
+            ->add('host')
         ->end()
         ->end()
         ;
@@ -110,10 +151,10 @@ class HostAdmin extends BaseAdmin
     function prePersist($object)
     {
         $object->setOptions(json_encode($object->getDHCPOption()));
-
+    
         return parent::preUpdate($object);
     }
-
+    
     /**
      * @param $object
      *
@@ -121,8 +162,15 @@ class HostAdmin extends BaseAdmin
      */
     function preUpdate($object)
     {
+        if ($object->getFixedAddress() && $object->getFixedIP() == false) {
+            $object->setFixedIP(true);
+        }
+        if (!$object->getFixedAddress() && $object->getFixedIP() == true) {
+            $object->setFixedIP(false);
+        }
+        
         $object->setOptions(json_encode($object->getDHCPOption()));
-
+    
         return parent::preUpdate($object);
     }
 }

+ 54 - 1
src/HostBundle/Entity/Host.php

@@ -34,7 +34,7 @@ class Host implements WorkflowInterface
     /**
      * @var string $name
      *
-     * @ORM\Column(type="string", length=100, unique=true)
+     * @ORM\Column(type="string", length=100, unique=true, nullable=true)
      */
     protected $mac;
 
@@ -78,6 +78,19 @@ class Host implements WorkflowInterface
      * @JMS\Exclude
      */
     protected $currentState = null;
+        
+    /**
+     * @ORM\Column(type="boolean", nullable=true)
+     */
+    protected $fixedIP = false;
+    
+    /**
+     * @ORM\ManyToOne(targetEntity="Host", fetch="EXTRA_LAZY")
+     * @ORM\JoinColumn(name="host_id", referencedColumnName="id", onDelete="SET NULL")
+     *
+     * @JMS\MaxDepth(1)
+     */
+    protected $host;
 
 
     /**
@@ -175,5 +188,45 @@ class Host implements WorkflowInterface
 
         return $this;
     }
+        
+    /**
+     * @return boolean
+     */
+    public function getFixedIP()
+    {
+        return $this->fixedIP;
+    }
+    
+    /**
+     * @param boolean $fixedIP
+     *
+     * @return Host
+     */
+    public function setFixedIP($fixedIP = null)
+    {
+        $this->fixedIP = $fixedIP;
+        
+        return $this;
+    }
+        
+    /**
+     * @return boolean
+     */
+    public function getHost()
+    {
+        return $this->host;
+    }
+    
+    /**
+     * @param Host $host
+     *
+     * @return Host
+     */
+    public function setHost($host = null)
+    {
+        $this->host = $host;
+        
+        return $this;
+    }
 
 }

+ 1 - 2
src/HostBundle/Entity/HostType.php

@@ -44,11 +44,10 @@ class HostType implements PreRemoveInterface
      */
     protected $shortname;
 
-
     /**
      * @ORM\OneToMany(targetEntity="Host", mappedBy="hostType")
      *
-     * @JMS\MaxDepth(1)
+     * @JMS\Exclude
      */
     protected $hosts;
 

+ 40 - 9
src/HostBundle/EventListener/AdminDHCPOption.php

@@ -2,12 +2,29 @@
 
 namespace HostBundle\EventListener;
 
-use Sonata\AdminBundle\Event\ConfigureEvent;
 use HostBundle\Traits\DHCPOptionTrait;
 use HostBundle\Utils\DHCPOptions;
+use HostBundle\Services\HostService;
+use Sonata\AdminBundle\Event\ConfigureEvent;
+use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
 
 class AdminDHCPOption
 {
+    
+    /**
+     * @var HostService
+     */
+    private $hostService;
+    
+    
+    /**
+     * @param HostService $hostService
+     */
+    public function __construct(HostService $hostService)
+    {
+        $this->hostService = $hostService;
+    }
 
     /**
      * @param ConfigureEvent $event
@@ -21,14 +38,31 @@ class AdminDHCPOption
                 $mapper->end()->end();
             }
             $options = array(
-                'translation_domain' => 'HostBundle'
+                'translation_domain' => 'HostBundle',
             );
             $mapper->tab('DHCP Option', $options)
                 ->with('DHCP Option', $options);
+            $fieldOptions = [
+                'required' => false,
+            ];
             foreach (DHCPOptions::getConstants() as $opt) {
-                $mapper->add($opt, 'text', array(
-                    'required'=> false,
-                ));
+                
+                if ($opt == 'fixed_address') {
+                    $freeIP = $this->hostService->getFreeFixedIP();
+                    $fixedAddress = $subject->getFixedAddress();
+                    if ($fixedAddress) {
+                        $freeIP[] = $fixedAddress;
+                    }
+                    sort($freeIP);
+                    $fieldOptions['choices'] = array_combine($freeIP, $freeIP);
+                    $fieldOptions['choice_translation_domain'] = false;
+                    $mapper->add($opt, ChoiceType::class, $fieldOptions);
+                    unset($fieldOptions['choices'], $fieldOptions['choice_translation_domain']);
+                    
+                    continue;
+                }
+                
+                $mapper->add($opt, TextType::class, $fieldOptions);
             }
             $mapper->end()->end();
         }
@@ -52,10 +86,7 @@ class AdminDHCPOption
                 ->with('DHCP Option', $options);
             foreach (DHCPOptions::getConstants() as $opt) {
                 if (!$mapper->has($opt)) {
-                    $mapper->add($opt, 'text', array(
-                        'required'=> false,
-                        'mapped' => false,
-                    ));
+                    $mapper->add($opt);
                 }
             }
             $mapper->end()->end();

+ 84 - 0
src/HostBundle/EventListener/AssignHostFixedAddressSubscriber.php

@@ -0,0 +1,84 @@
+<?php
+
+namespace HostBundle\EventListener;
+
+use Doctrine\Common\EventSubscriber;
+use Doctrine\ORM\Event\LifecycleEventArgs;
+use HostBundle\Entity\Host;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+class AssignHostFixedAddressSubscriber implements EventSubscriber
+{
+    
+    /**
+     * @var ContainerInterface
+     */
+    private $serviceContainer;
+    
+    
+    /**
+     * @param ContainerInterface $serviceContainer
+     */
+    public function __construct(ContainerInterface $serviceContainer)
+    {
+        $this->serviceContainer = $serviceContainer;
+    }
+
+    /**
+     * @return array
+     */
+    public function getSubscribedEvents()
+    {
+        return array(
+            'prePersist',
+            'preUpdate',
+        );
+    }
+
+    /**
+     * @param LifecycleEventArgs $args
+     */
+    public function prePersist(LifecycleEventArgs $args)
+    {
+        $this->execute($args);
+    }
+
+    /**
+     * @param LifecycleEventArgs $args
+     */
+    public function preUpdate(LifecycleEventArgs $args)
+    {
+        $this->execute($args, 'preUpdate');
+    }
+
+    /**
+     * @param LifecycleEventArgs $args
+     * @param string $eventName
+     */
+    public function execute(LifecycleEventArgs $args, $eventName = 'prePersist')
+    {
+        $entity = $args->getEntity();
+        if ($entity instanceof Host) {
+            
+            // Se debe asignar una IP fija ya que el host no tiene ninguna
+            if ($entity->getFixedIP() == true && !$entity->getFixedAddress()) {
+                $ip = $this->serviceContainer->get('dhcp.host_service')->getFirstFreeFixedIP();
+                $entity->setFixedAddress($ip);
+            }
+                        
+            // Se debe des-asignar una IP fija
+            if ($entity->getFixedIP() == false) {
+                $entity->setFixedAddress(null);
+            }
+            
+            $entity->setOptions(json_encode($entity->getDHCPOption()));
+
+            if ($eventName == 'preUpdate') {
+                $uow = $args->getEntityManager()->getUnitOfWork();
+                $meta = $args->getEntityManager()->getClassMetadata(get_class($entity));
+                $uow->recomputeSingleEntityChangeSet($meta, $entity);
+            }
+        }
+    }
+
+}

+ 11 - 2
src/HostBundle/Form/HostType.php

@@ -6,6 +6,7 @@ use HostBundle\Utils\DHCPOptions;
 use Symfony\Component\Form\AbstractType;
 use Symfony\Component\Form\FormBuilderInterface;
 use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
 
 class HostType extends AbstractType
 {
@@ -15,12 +16,20 @@ class HostType extends AbstractType
     public function buildForm(FormBuilderInterface $builder, array $options)
     {
         $builder
-            ->add('mac')
+            ->add('mac', TextType::class, [
+                'required' => false,
+            ])
             ->add('hostType')
+            ->add('host', null, [
+                'required' => false,
+            ])
             ->add('state')
+            ->add('fixedIP', TextType::class, [
+                'required' => false,
+            ])
             ;
         foreach (DHCPOptions::getConstants() as $opt) {
-            $builder->add($opt, 'text', array(
+            $builder->add($opt, TextType::class, array(
                 'required'=> false,
             ));
         }

+ 14 - 1
src/HostBundle/Resources/config/services.yml

@@ -6,7 +6,8 @@ services:
         tags:
             - { name: sonata.admin, manager_type: orm, group: Host, label: Host, label_catalogue: HostBundle, label_translator_strategy: sonata.admin.label.strategy.underscore }
         calls:
-            - [setTranslationDomain, [IPv4Bundle]]
+            - [setTranslationDomain, [HostBundle]]
+            - [setTemplate, [edit, "HostBundle:CRUD:edit.html.twig"]]
         public: true
 
     sonata.admin.host_type:
@@ -20,6 +21,18 @@ services:
 
     dhcp_option_admin:
        class: HostBundle\EventListener\AdminDHCPOption
+       arguments: [ "@dhcp.host_service" ]
        tags:
            - { name: kernel.event_listener, event: sonata.admin.event.configure.form, method: configureFormFields }
            - { name: kernel.event_listener, event: sonata.admin.event.configure.show, method: configureShowFields }
+           
+    dhcp.host_service:
+        class: HostBundle\Services\HostService
+        arguments: [ "@doctrine.orm.entity_manager", "@pool_ipv4_service" ]
+        
+    dhcp.assign_host_fixed_address.subscriber:
+        class: HostBundle\EventListener\AssignHostFixedAddressSubscriber
+        arguments: [ "@service_container" ]
+        tags:
+            - { name: doctrine.event_subscriber, connection: default }    
+        

+ 9 - 1
src/HostBundle/Resources/translations/HostBundle.es.yml

@@ -42,6 +42,8 @@ form:
     label_log_servers: Log Servers
     label_time_servers: Time Servers
     label_status: Estado
+    label_fixed_address: Fixed Address
+    label_host: Host
 
 list:
     label_mac: Mac
@@ -62,7 +64,9 @@ list:
     label_state: Estado
     label_extra_data: Extra Data
     label_status: Estado
-
+    label_host: Host
+    label_options_fixed_address: IP
+    
 show:
     label_mac: Mac
     label_options: Opciones
@@ -99,6 +103,8 @@ show:
     label_log_servers: Log Servers
     label_time_servers: Time Servers
     label_status: Estado
+    label_fixed_address: Fixed Address
+    label_host: Host
 
 filter:
     label_mac: Mac
@@ -114,6 +120,8 @@ filter:
     label_extra_data: Extra Data
     label_allowed_host_type: Tipo de Host permitido
     label_status: Estado
+    label_host_type: Tipo de Host
+    label_options_fixed_address: IP
 
 breadcrumb:
     link_host_list: Listado Host

+ 33 - 0
src/HostBundle/Resources/views/CRUD/edit.html.twig

@@ -0,0 +1,33 @@
+{% extends "@SonataAdmin/CRUD/edit.html.twig" %}
+
+{% block javascripts %}
+
+{{ parent() }}
+
+<script type="text/javascript">
+
+$(document).ready(function() {
+
+    showHostField();
+
+    $("select[id$='hostType']").on('change', showHostField);
+
+});
+
+function showHostField()
+{
+    var $hostTypeField = $("select[id$='hostType'] :selected");
+    var $hostField = $("div.form-group[id$='host']");
+
+    if ($hostTypeField.html() === 'Cablemodem') {
+        $hostField.hide();
+    } else {
+        $hostField.show();
+    }
+
+    return false;
+}
+
+</script>
+
+{% endblock javascripts %}

+ 89 - 0
src/HostBundle/Services/HostService.php

@@ -0,0 +1,89 @@
+<?php
+
+namespace HostBundle\Services;
+
+use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\EntityRepository;
+use HostBundle\Entity\Host;
+use IPv4Bundle\Services\PoolService;
+use KeaBundle\Entity\Lease4;
+
+class HostService
+{
+    
+    /**
+     * @var EntityManager
+     */
+    private $em;
+    
+    /**
+     * @var EntityRepository
+     */
+    private $hostRepository;
+    
+    /**
+     * @var EntityRepository
+     */
+    private $lease4Repository;
+    
+    /**
+     * @var PoolService
+     */
+    private $poolService;
+    
+    
+    /**
+     * @param EntityManager $em
+     * @param PoolService $poolService
+     */
+    public function __construct(EntityManager $em, PoolService $poolService)
+    {
+        $this->em = $em;
+        $this->hostRepository = $em->getRepository(Host::class);
+        $this->lease4Repository = $em->getRepository(Lease4::class);
+        $this->poolService = $poolService;
+    }
+    
+    /**
+     * @return string
+     */
+    public function getFirstFreeFixedIP()
+    {
+        $diff = $this->getFreeFixedIP();
+        if (count($diff)) {
+            return current($diff);
+        }
+        
+        return null;
+    }
+    
+    /**
+     * @return array
+     */
+    public function getFreeFixedIP($hostFixed = true)
+    {
+        $range = $this->poolService->getStaticPoolIPRange();
+        $leases = $this->lease4Repository->getAllAddress();
+        $hostsFixedIP = $hostFixed ? $this->getHostsFixedIp() : [];
+        
+        return array_diff($range, $leases, $hostsFixedIP);
+    }
+    
+    /**
+     * @return array
+     */
+    public function getHostsFixedIp()
+    {
+        $hostsFixedIP = [];
+        $hosts = $this->hostRepository->findBy([
+            'fixedIP' => true,
+        ]);
+        foreach ($hosts as $host) {
+            if ($host->getFixedAddress()) {
+                $hostsFixedIP[] = $host->getFixedAddress();
+            }
+        }
+        
+        return $hostsFixedIP;
+    }
+}

+ 10 - 0
src/HostBundle/Traits/DHCPOptionTrait.php

@@ -217,4 +217,14 @@ trait DHCPOptionTrait
         return @$this->json_dhcp_option_config['time_servers'];
     }
 
+    function setFixedAddress($value)
+    {
+        $this->json_dhcp_option_config['fixed_address'] = $value;
+    }
+
+    function getFixedAddress()
+    {
+        return @$this->json_dhcp_option_config['fixed_address'];
+    }
+
 }

+ 1 - 0
src/HostBundle/Utils/DHCPOptions.php

@@ -9,6 +9,7 @@ class DHCPOptions
 
     use ChoiceTrait;
 
+    const DHCP_FIXED_ADDRESS = 'fixed_address';
     const DHCP_FILENAME = 'filename';
     const DHCP_SUBNET_MASK = 'subnet_mask';
     const DHCP_TIME_OFFSET = 'time_offset';

+ 5 - 0
src/IPv4Bundle/Resources/config/services.yml

@@ -26,3 +26,8 @@ services:
         calls:
             - [setTranslationDomain, [IPv4Bundle]]
         public: true
+        
+    pool_ipv4_service:
+        class: IPv4Bundle\Services\PoolService
+        arguments: [ '@doctrine.orm.entity_manager' ]
+        public: true

+ 73 - 0
src/IPv4Bundle/Services/PoolService.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace IPv4Bundle\Services;
+
+use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\EntityRepository;
+use IPv4Bundle\Entity\Pool;
+use KeaBundle\Entity\Lease4;
+
+class PoolService
+{
+    
+    /**
+     * @var EntityRepository
+     */
+    private $poolRepository;
+    
+    
+    /**
+     * @param EntityManager $em
+     */
+    public function __construct(EntityManager $em)
+    {
+        $this->poolRepository = $em->getRepository(Pool::class);
+    }
+        
+    /**
+     * Retorna el primer pool donde se encuentra el lease
+     *
+     * @param Lease4 $lease
+     *
+     * @return Pool
+     */
+    public function getPoolFromLease(Lease4 $lease)
+    {
+        $address = ip2long($lease->getAddress());
+        $pools = $this->poolRepository->findAll();
+        foreach ($pools as $pool) {
+            $firstIp = ip2long($pool->getFirstIp());
+            $lastIp =  ip2long($pool->getLastIp());
+            
+            if ($firstIp <= $address && $address <= $lastIp) {
+                return $pool;
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * @return array
+     */
+    public function getStaticPoolIPRange()
+    {
+        $range = [];
+        $pools = $this->poolRepository->findBy([
+            'isStatic' => true,
+        ]);
+        foreach ($pools as $pool) {
+            $range[] = $pool->getFirstIp();
+            $firstIp = ip2long($pool->getFirstIp());
+            $lastIp =  ip2long($pool->getLastIp());
+            $currentIP = $firstIp + 1;
+            while ($currentIP <= $lastIp) {
+                $range[] = long2ip($currentIP);
+                $currentIP++;
+            }
+        }
+        
+        return $range;
+    }
+    
+}

+ 128 - 0
src/KeaBundle/Admin/Lease4Admin.php

@@ -0,0 +1,128 @@
+<?php
+
+namespace KeaBundle\Admin;
+
+use Base\AdminBundle\Admin\BaseAdmin;
+use HostBundle\Entity\Host;
+use IPv4Bundle\Entity\Pool;
+use IPv4Bundle\Entity\SubNet;
+use Sonata\AdminBundle\Datagrid\DatagridMapper;
+use Sonata\AdminBundle\Datagrid\ListMapper;
+use Sonata\AdminBundle\Form\FormMapper;
+use Sonata\AdminBundle\Show\ShowMapper;
+use Sonata\AdminBundle\Route\RouteCollection;
+
+class Lease4Admin extends BaseAdmin
+{
+    /**
+     * @param DatagridMapper $datagridMapper
+     */
+    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
+    {
+        $datagridMapper
+            ->add('address', 'doctrine_orm_callback', array(
+                'callback' => function($queryBuilder, $alias, $field, $value) {
+                    if (!$value['value']) {
+                        return;
+                    }
+
+                    $queryBuilder
+                        ->andWhere("{$alias}.address = :address")
+                        ->setParameter('address', ip2long($value['value']));
+
+                    return true;
+                },
+            ))
+            ->add('hwaddr', 'doctrine_orm_callback', array(
+                'callback' => function($queryBuilder, $alias, $field, $value) {
+                    if (!$value['value']) {
+                        return;
+                    }
+                    
+                    $queryBuilder->andWhere("{$alias}.hwaddr = :hwaddr");
+                    $queryBuilder->setParameter('hwaddr', hex2bin($value['value']));
+
+                    return true;
+                },
+            ))
+        ;
+    }
+
+    /**
+     * @param ListMapper $listMapper
+     */
+    protected function configureListFields(ListMapper $listMapper)
+    {
+        $listMapper
+            ->add('address')
+            ->add('client_id')
+            ->add('valid_lifetime')
+            ->add('expire');
+            
+        $this->addFields($listMapper);
+            
+        $listMapper->add('_action', null, array(
+                'actions' => array(
+                    'show' => array(),
+                ),
+            ))
+        ;
+    }
+
+    /**
+     * @param ShowMapper $showMapper
+     */
+    protected function configureShowFields(ShowMapper $showMapper)
+    {
+        $showMapper
+            ->add('address')
+            ->add('client_id')
+            ->add('valid_lifetime')
+            ->add('expire')
+        ;
+        
+        $this->addFields($showMapper, 'show');
+    }
+    
+    protected function addFields($mapper, $action = 'list')
+    {
+        $mapper
+            ->add('hwaddr', null, [
+                'template' => 'BaseAdminBundle:CRUD:show_entity.html.twig',
+                'data' => [
+                    'class' => Host::class,
+                    'field' => 'mac',
+                    'action' => $action,
+                ],
+            ])
+            ->add('pool', null, [
+                'template' => 'KeaBundle:CRUD:lease_pool_ipv4.html.twig',
+                'data' => [
+                    'class' => Pool::class,
+                    'field' => 'name',
+                    'action' => $action,
+                ],
+            ])
+            ->add('subnet', null, [
+                'template' => 'KeaBundle:CRUD:lease_subnet_ipv4.html.twig',
+                'data' => [
+                    'class' => SubNet::class,
+                    'field' => 'address',
+                    'action' => $action,
+                ],
+            ]);
+    }
+    
+    /**
+     * @param RouteCollection $collection
+     */
+    protected function configureRoutes(RouteCollection $collection)
+    {
+        $collection
+            ->remove('create')
+            ->remove('edit')
+            ->remove('delete')
+        ;
+    }
+    
+}

+ 148 - 0
src/KeaBundle/Entity/Lease4.php

@@ -0,0 +1,148 @@
+<?php
+
+namespace KeaBundle\Entity;
+
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * @ORM\Table(name="kea.lease4")
+ * @ORM\Entity(repositoryClass="KeaBundle\Repository\Lease4Repository")
+ */
+class Lease4
+{
+
+    /**
+     * @var int
+     *
+     * @ORM\Column(name="address", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue(strategy="AUTO")
+     */
+    private $address;
+
+    /**
+     * @var int
+     *
+     * @ORM\Column(type="string")
+     */
+    private $hwaddr;
+    
+    /**
+     * @var int
+     *
+     * @ORM\Column(type="string")
+     */
+    private $client_id;
+    
+    /**
+     * @var int
+     *
+     * @ORM\Column(type="integer")
+     */
+    private $valid_lifetime;
+    
+    /**
+     * @var int
+     *
+     * @ORM\Column(type="datetime")
+     */
+    private $expire;
+    
+    
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->getAddress();
+    }
+    
+    /**
+     * @return string
+     */
+    public function getAddress()
+    {
+        return long2ip($this->address);
+    }
+    
+    /**
+     * @return string
+     */    
+    public function getHwaddr()
+    {
+        return bin2hex($this->hwaddr);
+    }
+    
+    /**
+     * @param string $hwaddr
+     *
+     * @return Lease4
+     */
+    public function setHwaddr($hwaddr)
+    {
+        $this->hwaddr = $hwaddr;
+        
+        return $this;
+    }
+    
+    /**
+     * @return string
+     */     
+    public function getClientId()
+    {
+        return bin2hex($this->client_id);
+    }
+    
+    /**
+     * @param string $client_id
+     *
+     * @return Lease4
+     */
+    public function setClientId($client_id)
+    {
+        $this->client_id = $client_id;
+        
+        return $this;
+    }
+    
+    /**
+     * @return int
+     */    
+    public function getValidLifetime()
+    {
+        return $this->valid_lifetime;
+    }
+    
+    /**
+     * @param int $valid_lifetime
+     *
+     * @return Lease4
+     */
+    public function setValidLifetime($valid_lifetime)
+    {
+        $this->valid_lifetime = $valid_lifetime;
+        
+        return $this;
+    }
+    
+    /**
+     * @return DateTime
+     */     
+    public function getExpire()
+    {
+        return $this->expire;
+    }
+    
+    /**
+     * @param DateTime $expire
+     *
+     * @return Lease4
+     */
+    public function setExpire($expire)
+    {
+        $this->expire = $expire;
+        
+        return $this;
+    }
+    
+}

+ 21 - 0
src/KeaBundle/Repository/Lease4Repository.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace KeaBundle\Repository;
+
+class Lease4Repository extends \Doctrine\ORM\EntityRepository
+{
+
+    /**
+     * @return array
+     */
+    public function getAllAddress()
+    {
+        $qb = $this->createQueryBuilder('Lease4');
+        $leases = $qb->getQuery()->getResult();
+        
+        return array_map(function ($lease) {
+            return $lease->getAddress();
+        }, $leases);
+    }
+
+}

+ 17 - 2
src/KeaBundle/Resources/config/services.yml

@@ -1,7 +1,7 @@
 services:
     kea.config:
         class: KeaBundle\Services\KeaConfigService
-        arguments: ["@webservice", "@doctrine.orm.entity_manager"]
+        arguments: ["@doctrine.orm.entity_manager", "%database_user%", "%database_password%"]
 
     sonata.admin.kea_config:
         class: KeaBundle\Admin\ConfigAdmin
@@ -10,4 +10,19 @@ services:
             - { name: sonata.admin, manager_type: orm, group: Kea, label: Config, label_catalogue: KeaBundle, label_translator_strategy: sonata.admin.label.strategy.underscore, audit: false }
         calls:
             - [setTranslationDomain, [KeaBundle]]
-        public: true
+        public: true
+
+    sonata.admin.lease_4:
+        class: KeaBundle\Admin\Lease4Admin
+        arguments: [~, KeaBundle\Entity\Lease4, BaseAdminBundle:CRUD]
+        tags:
+            - { name: sonata.admin, manager_type: orm, group: Kea, label: Lease4, label_catalogue: KeaBundle, label_translator_strategy: sonata.admin.label.strategy.underscore, audit: false }
+        calls:
+            - [setTranslationDomain, [KeaBundle]]
+        public: true
+
+    kea.twig_ipv4_pool_extension:
+       class: KeaBundle\Twig\PoolIPv4Extension
+       arguments: [ '@pool_ipv4_service' ]
+       tags:
+           - { name: twig.extension }

+ 19 - 1
src/KeaBundle/Resources/translations/KeaBundle.es.yml

@@ -1,5 +1,6 @@
 Kea: Kea
 Config: Configuración
+Lease4: Leases ipv4
 
 form:
     label_description: Descripción
@@ -15,6 +16,7 @@ breadcrumb:
     link_config_list: Listado de Configuraciones
     link_config_delete: Eliminar Configuración
     link_config_create: Configurar KEA
+    link_lease4_list: Listado Leases
     
 list:
     label_description: Descripción
@@ -22,18 +24,34 @@ list:
     label_created: Creado
     label_template: Plantilla
     label__action: Acciones
+    label_address: Address
+    label_hwaddr: Hwaddr
+    label_client_id: Client id
+    label_valid_lifetime: Valid lifetime
+    label_expire: Expire
+    label_pool: Pool
+    label_subnet: Subnet
 
 show:
     label_description: Descripción
     label_dhcp: DHCP
     label_created: Creado
     label_template: Plantilla
+    label_address: Address
+    label_hwaddr: Hwaddr
+    label_client_id: Client id
+    label_valid_lifetime: Valid lifetime
+    label_expire: Expire
+    label_pool: Pool
+    label_subnet: Subnet
 
 filter:
     label_description: Descripción
     label_dhcp: DHCP
     label_created: Creado
     label_template: Plantilla
+    label_address: Address
+    label_hwaddr: Hwaddr
 
 msg_import_kea_config: Obtener configuración de Kea
 select_dhcp_and_get_config: Seleccionar DHCP y obtener configuración
@@ -61,4 +79,4 @@ api:
     reload_config_help: Genera configuración KEA y la envía hacia el KEA del DHCP seleccionado.
     reload_hooks_help: Carga nuevamente las librerías de Hooks.
     
-alert_select_dhcp: Seleccione un DHCP de KEA    
+alert_select_dhcp: Seleccione un DHCP de KEA    

+ 4 - 0
src/KeaBundle/Resources/views/CRUD/lease_pool_ipv4.html.twig

@@ -0,0 +1,4 @@
+{% extends 'BaseAdminBundle:CRUD:show_entity.html.twig' %}
+
+{% set pool = pool_ipv4(object) %}
+{% set value = pool is not null ? pool.getName() : '' %}

+ 4 - 0
src/KeaBundle/Resources/views/CRUD/lease_subnet_ipv4.html.twig

@@ -0,0 +1,4 @@
+{% extends 'BaseAdminBundle:CRUD:show_entity.html.twig' %}
+
+{% set pool = pool_ipv4(object) %}
+{% set value = pool is not null ? pool.getSubNet().getAddress() : '' %}

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

@@ -45,7 +45,8 @@ class BaseKea implements KeaConfigInterface
                 'arguments' => array(
                     'Dhcp4' => [
                         'control-socket' => $this->controlSocketConfig(),
-                        'lease-database' =>$this->leaseDatabaseConfig(),
+                        'lease-database' => $this->leaseDatabaseConfig($data),
+                        'hosts-database' => $this->leaseDatabaseConfig($data),
                         'subnet4' => $this->subnet4,
                         'hooks-libraries' => $this->hooks_libraries,
                         'interfaces-config' => $this->getInterfacesConfig(),
@@ -83,6 +84,12 @@ class BaseKea implements KeaConfigInterface
                 'subnet' => $subnet->getAddress(),
                 'pools' => $pools,
             ];
+            
+            $nextServer = $subnet->getNextServer();
+            if ($nextServer != '') {
+                $subnetConf['next-server'] = $nextServer;
+            }
+            
             if ($client_class != '') {
                 $subnetConf['client-class'] = $client_class;
             }
@@ -174,13 +181,24 @@ class BaseKea implements KeaConfigInterface
     /**
      * @return array
      */
-    private function leaseDatabaseConfig()
+    private function leaseDatabaseConfig($data, $type = 'mysql')
     {
-        /* "lease-database": {"lfc-interval": 3600,"type": "memfile"} */
-        return array(
-            'lfc-interval' => 3600,
-            'type' => 'memfile'
-        );
+        if ($type == 'mysql') {
+            $config = array(
+                "host" => $data['db']['host'],
+                "name" => $data['db']['name'],
+                "user" => $data['db']['user'],
+                "password" => $data['db']['password'],
+                "type" => "mysql",
+            );
+        } elseif ($type == 'memfile') {
+            $config = array(
+                'lfc-interval' => 3600,
+                'type' => 'memfile'
+            );
+        }
+        
+        return $config;
     }
 
     /**

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

@@ -6,7 +6,6 @@ use Doctrine\ORM\EntityManager;
 use Doctrine\ORM\EntityRepository;
 use DHCPBundle\Entity\DHCP;
 use KeaBundle\Interfaces\KeaConfigInterface;
-use WebserviceBundle\Services\Webservice;
 
 class KeaConfigService
 {
@@ -27,21 +26,28 @@ class KeaConfigService
     private $hostRepository;
 
     /**
-     * @var Webservice
+     * @var array
      */
-    private $webService;
-
+    private $databaseConfig;
+    
 
     /**
-     * @param Webservice $ws
      * @param EntityManager $em
+     * @param string $databaseUser
+     * @param string $databasePassword
      */
-    public function __construct(Webservice $ws, EntityManager $em)
+    public function __construct(EntityManager $em, $databaseUser, $databasePassword)
     {
         $this->dhcpRepository = $em->getRepository('DHCPBundle:DHCP');
         $this->subnetRepository = $em->getRepository('IPv4Bundle:SubNet');
         $this->hostRepository = $em->getRepository('HostBundle:Host');
-        $this->webService = $ws;
+        
+        $this->databaseConfig = [
+            'host' => 'mysql',
+            'name' => 'kea',
+            'user' => $databaseUser,
+            'password' => $databasePassword,
+        ];
     }
 
     /**
@@ -63,6 +69,7 @@ class KeaConfigService
                     'hosts' => $this->hostRepository->findAll(),
                     'subnets' => $this->subnetRepository->findAll(),
                     'library' => $library,
+                    'db' => $this->databaseConfig,
                 ];
                 $config = $keaConfig->getConfig($data);
             }

+ 53 - 0
src/KeaBundle/Twig/PoolIPv4Extension.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace KeaBundle\Twig;
+
+use IPv4Bundle\Services\PoolService;
+use KeaBundle\Entity\Lease4;
+
+class PoolIPv4Extension extends \Twig_Extension
+{
+
+    /**
+     * @var PoolService
+     */
+    private $poolService;
+
+
+    /**
+     * @param PoolService $poolService
+     */
+    public function __construct(PoolService $poolService)
+    {
+        $this->poolService = $poolService;
+    }
+
+    /**
+     * @return array
+     */
+    public function getFunctions()
+    {
+        return array(
+            new \Twig_SimpleFunction('pool_ipv4', array($this, 'getPool')),
+        );
+    }
+
+    /**
+     * @param Lease4 $object
+     *
+     * @return string
+     */
+    public function getPool(Lease4 $object)
+    {
+        return $this->poolService->getPoolFromLease($object);
+    }
+
+    /**
+     * @return string
+     */
+    public function getName()
+    {
+        return 'pool_ipv4_extension';
+    }
+
+}