[icinga-checkins] icinga.org: icingaweb2-module-director/master: IcingaHost: introduce API keys

git at icinga.org git at icinga.org
Tue Jul 26 10:00:25 CEST 2016


Module: icingaweb2-module-director
Branch: master
Commit: 439757d4640851a18732705b5222f5569ce5a73d
URL:    https://git.icinga.org/?p=icingaweb2-module-director.git;a=commit;h=439757d4640851a18732705b5222f5569ce5a73d

Author: Thomas Gelf <thomas at gelf.net>
Date:   Tue Jul 26 09:52:55 2016 +0200

IcingaHost: introduce API keys

---

 library/Director/Objects/IcingaHost.php            |   28 +++++++
 schema/mysql-migrations/upgrade_101.sql            |    7 ++
 schema/mysql.sql                                   |    2 +
 schema/pgsql-migrations/upgrade_101.sql            |    9 ++
 schema/pgsql.sql                                   |    2 +
 .../library/Director/Objects/IcingaHostTest.php    |   86 +++++++++++++++++++-
 6 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/library/Director/Objects/IcingaHost.php b/library/Director/Objects/IcingaHost.php
index e411819..a0cb9e8 100644
--- a/library/Director/Objects/IcingaHost.php
+++ b/library/Director/Objects/IcingaHost.php
@@ -3,6 +3,8 @@
 namespace Icinga\Module\Director\Objects;
 
 use Icinga\Data\Db\DbConnection;
+use Icinga\Exception\NotFoundError;
+use Icinga\Module\Director\Db;
 use Icinga\Module\Director\IcingaConfig\IcingaConfig;
 use Icinga\Module\Director\Web\Form\DirectorObjectForm;
 
@@ -42,6 +44,7 @@ class IcingaHost extends IcingaObject
         'has_agent'             => null,
         'master_should_connect' => null,
         'accept_config'         => null,
+        'api_key'               => null,
     );
 
     protected $relations = array(
@@ -230,9 +233,34 @@ class IcingaHost extends IcingaObject
      *
      * @return string
      */
+    protected function renderApi_key()
+    {
+        return '';
+    }
+
+    /**
+     * Internal property, will not be rendered
+     *
+     * @return string
+     */
     protected function renderAccept_config()
     {
         // @codingStandardsIgnoreEnd
         return '';
     }
+
+    public static function loadWithApiKey($key, Db $db)
+    {
+        $query = $db->getDbAdapter()
+            ->select()
+            ->from('icinga_host')
+            ->where('api_key = ?', $key);
+
+        $result = self::loadAll($db, $query);
+        if (count($result) !== 1) {
+            throw new NotFoundError('Got invalid API key "%s"', $key);
+        }
+
+        return current($result);
+    }
 }
diff --git a/schema/mysql-migrations/upgrade_101.sql b/schema/mysql-migrations/upgrade_101.sql
new file mode 100644
index 0000000..bbe1817
--- /dev/null
+++ b/schema/mysql-migrations/upgrade_101.sql
@@ -0,0 +1,7 @@
+ALTER TABLE icinga_host
+  ADD COLUMN api_key VARCHAR(40) DEFAULT NULL AFTER accept_config,
+  ADD UNIQUE KEY api_key (api_key);
+
+INSERT INTO director_schema_migration
+  (schema_version, migration_time)
+  VALUES (101, NOW());
diff --git a/schema/mysql.sql b/schema/mysql.sql
index c6ec60f..bfdd1a8 100644
--- a/schema/mysql.sql
+++ b/schema/mysql.sql
@@ -447,8 +447,10 @@ CREATE TABLE icinga_host (
   has_agent ENUM('y', 'n') DEFAULT NULL,
   master_should_connect ENUM('y', 'n') DEFAULT NULL,
   accept_config ENUM('y', 'n') DEFAULT NULL,
+  api_key VARCHAR(40) DEFAULT NULL,
   PRIMARY KEY (id),
   UNIQUE INDEX object_name (object_name),
+  UNIQUE INDEX api_key (api_key),
   KEY search_idx (display_name),
   CONSTRAINT icinga_host_zone
     FOREIGN KEY zone (zone_id)
diff --git a/schema/pgsql-migrations/upgrade_101.sql b/schema/pgsql-migrations/upgrade_101.sql
new file mode 100644
index 0000000..4243c01
--- /dev/null
+++ b/schema/pgsql-migrations/upgrade_101.sql
@@ -0,0 +1,9 @@
+ALTER TABLE icinga_host
+  ADD COLUMN api_key character varying(40) DEFAULT NULL;
+
+CREATE UNIQUE INDEX host_api_key ON icinga_host (api_key);
+
+INSERT INTO director_schema_migration
+  (schema_version, migration_time)
+  VALUES (101, NOW());
+
diff --git a/schema/pgsql.sql b/schema/pgsql.sql
index 2569386..dab834b 100644
--- a/schema/pgsql.sql
+++ b/schema/pgsql.sql
@@ -575,6 +575,7 @@ CREATE TABLE icinga_host (
   has_agent enum_boolean DEFAULT NULL,
   master_should_connect enum_boolean DEFAULT NULL,
   accept_config enum_boolean DEFAULT NULL,
+  api_key character varying(40) DEFAULT NULL,
   PRIMARY KEY (id),
   CONSTRAINT icinga_host_zone
   FOREIGN KEY (zone_id)
@@ -604,6 +605,7 @@ CREATE TABLE icinga_host (
 );
 
 CREATE UNIQUE INDEX object_name_host ON icinga_host (object_name, zone_id);
+CREATE UNIQUE INDEX host_api_key ON icinga_host (api_key);
 CREATE INDEX host_zone ON icinga_host (zone_id);
 CREATE INDEX host_timeperiod ON icinga_host (check_period_id);
 CREATE INDEX host_check_command ON icinga_host (check_command_id);
diff --git a/test/php/library/Director/Objects/IcingaHostTest.php b/test/php/library/Director/Objects/IcingaHostTest.php
index ccf7a58..b8705b0 100644
--- a/test/php/library/Director/Objects/IcingaHostTest.php
+++ b/test/php/library/Director/Objects/IcingaHostTest.php
@@ -6,6 +6,7 @@ use Icinga\Module\Director\IcingaConfig\IcingaConfig;
 use Icinga\Module\Director\Objects\IcingaHost;
 use Icinga\Module\Director\Objects\IcingaZone;
 use Icinga\Module\Director\Test\BaseTestCase;
+use Icinga\Exception\IcingaException;
 
 class IcingaHostTest extends BaseTestCase
 {
@@ -392,6 +393,89 @@ class IcingaHostTest extends BaseTestCase
 
     }
 
+    public function testWhetherTwoHostsCannotBeStoredWithTheSameApiKey()
+    {
+        if ($this->skipForMissingDb()) {
+            return;
+        }
+
+        $db = $this->getDb();
+        $a = IcingaHost::create(array(
+            'object_name' => '___TEST___a',
+            'object_type' => 'object',
+            'api_key' => 'a'
+        ), $db);
+        $b = IcingaHost::create(array(
+            'object_name' => '___TEST___b',
+            'object_type' => 'object',
+            'api_key' => 'a'
+        ), $db);
+
+        $a->store();
+        try {
+            $b->store();
+        } catch (IcingaException $e) {
+            $msg = $e->getMessage();
+            $matchMysql = strpos(
+                $msg,
+                "Duplicate entry 'a' for key 'api_key'"
+            ) !== false;
+
+            $matchPostgres = strpos(
+                $msg,
+                'Unique violation'
+            ) !== false;
+
+            $this->assertTrue(
+                $matchMysql || $matchPostgres,
+                'Exception message does not tell about unique constraint violation'
+            );
+            $a->delete();
+        }
+    }
+
+    public function testWhetherHostCanBeLoadedWithValidApiKey()
+    {
+        if ($this->skipForMissingDb()) {
+            return;
+        }
+
+        $db = $this->getDb();
+        $a = IcingaHost::create(array(
+            'object_name' => '___TEST___a',
+            'object_type' => 'object',
+            'api_key' => 'a1a1a1'
+        ), $db);
+        $b = IcingaHost::create(array(
+            'object_name' => '___TEST___b',
+            'object_type' => 'object',
+            'api_key' => 'b1b1b1'
+        ), $db);
+        $a->store();
+        $b->store();
+
+        $this->assertEquals(
+            IcingaHost::loadWithApiKey('b1b1b1', $db)->object_name,
+            '___TEST___b'
+        );
+
+        $a->delete();
+        $b->delete();
+    }
+
+    /**
+     * @expectedException \Icinga\Exception\NotFoundError
+     */
+    public function testWhetherInvalidApiKeyThrows404()
+    {
+        if ($this->skipForMissingDb()) {
+            return;
+        }
+
+        $db = $this->getDb();
+        IcingaHost::loadWithApiKey('No___such___key', $db);
+    }
+
     protected function getDummyRelatedProperties()
     {
         return array(
@@ -434,7 +518,7 @@ class IcingaHostTest extends BaseTestCase
     {
         if ($this->hasDb()) {
             $db = $this->getDb();
-            $kill = array($this->testHostName, '___TEST___parent');
+            $kill = array($this->testHostName, '___TEST___parent', '___TEST___a', '___TEST___b');
             foreach ($kill as $name) {
                 if (IcingaHost::exists($name, $db)) {
                     IcingaHost::load($name, $db)->delete();



More information about the icinga-checkins mailing list