]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[2541] add createZone() to DataSourceClient interface
authorJelte Jansen <jelte@isc.org>
Mon, 10 Dec 2012 19:15:21 +0000 (20:15 +0100)
committerJelte Jansen <jelte@isc.org>
Mon, 10 Dec 2012 19:19:20 +0000 (20:19 +0100)
Note: currently called createZone so as not to interfere with an existing addZone() call in MemoryClient.
Instead of pure virtual I made it have a default 'NotImplemented' method.
Also, the DatabaseClient holds the transaction (not the SQLite3Accessor); we could do it on that level but we already have a transaction API on a higher level and it makes a little bit more sense to me to do it there

src/lib/datasrc/client.h
src/lib/datasrc/database.cc
src/lib/datasrc/database.h
src/lib/datasrc/tests/client_unittest.cc
src/lib/datasrc/tests/database_unittest.cc

index 3756a6858a9ab4d14fd55fc56c03d00b3c457e3c..e1cde588a9676f738d67c7884d135e249af33d12 100644 (file)
@@ -378,6 +378,20 @@ public:
         isc_throw(isc::NotImplemented,
                   "Data source doesn't support getZoneCount");
     }
+
+    // It first checks if the specified name of the zone exists.  If it
+    // exists it returns false; otherwise it adds information of the
+    // new zone in backend-dependent manner and returns true.
+    // The DB-based version of this method would perform the check and add in
+    // a single transaction.
+    //
+    // Throws on any unexpected failure.
+    // Default implementation throws isc::NotImplemented
+
+    virtual bool createZone(const dns::Name&) {
+        isc_throw(isc::NotImplemented,
+                  "Data source doesn't support addZone");
+    };
 };
 }
 }
index fbada44a33cacbc914fb7cfcc2dee4022ce0d2e0..de432130dfee328a51975e0620bebfac51af16e7 100644 (file)
@@ -43,6 +43,30 @@ using boost::scoped_ptr;
 
 namespace isc {
 namespace datasrc {
+// RAII-style transaction holder; roll back the transaction unless explicitely committed
+namespace {
+class TransactionHolder {
+public:
+    TransactionHolder(DatabaseAccessor& accessor) : accessor_(accessor),
+                                                    committed_(false)
+    {
+        accessor_.startTransaction();
+    }
+    ~TransactionHolder() {
+        if (!committed_) {
+            accessor_.rollback();
+        }
+    }
+    void commit() {
+        accessor_.commit();
+        committed_ = true;
+    }
+private:
+    DatabaseAccessor& accessor_;
+    bool committed_;
+};
+} // end unnamed namespace
+
 
 DatabaseClient::DatabaseClient(RRClass rrclass,
                                boost::shared_ptr<DatabaseAccessor>
@@ -80,6 +104,18 @@ DatabaseClient::findZone(const Name& name) const {
     return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
 }
 
+bool
+DatabaseClient::createZone(const Name& name) {
+    TransactionHolder transaction(*accessor_);
+    std::pair<bool, int> zone(accessor_->getZone(name.toText()));
+    if (zone.first) {
+        return (false);
+    }
+    accessor_->addZone(name.toText());
+    transaction.commit();
+    return (true);
+}
+
 DatabaseClient::Finder::Finder(boost::shared_ptr<DatabaseAccessor> accessor,
                                int zone_id, const isc::dns::Name& origin) :
     accessor_(accessor),
index a3b49f56bd2e25235f11f043be76008064f2a0a3..6546bdeb478c823e9ef2c33adff43c4ec648456c 100644 (file)
@@ -1393,6 +1393,8 @@ public:
     ///     should use it as a ZoneFinder only.
     virtual FindResult findZone(const isc::dns::Name& name) const;
 
+    virtual bool createZone(const isc::dns::Name&);
+
     /// \brief Get the zone iterator
     ///
     /// The iterator allows going through the whole zone content. If the
index 87ab5e05dbdc5361603fca01c271e9e4d5df5870..915e3b7ce1e9fdfa5be9b46981c931c5fdd070e4 100644 (file)
@@ -60,4 +60,8 @@ TEST_F(ClientTest, defaultGetZoneCount) {
     EXPECT_THROW(client_.getZoneCount(), isc::NotImplemented);
 }
 
+TEST_F(ClientTest, defaultCreateZone) {
+    EXPECT_THROW(client_.createZone(Name("example.com.")), isc::NotImplemented);
+}
+
 }
index 05d825e2dd15cb38eff4af85c864cf1903efade4..8494096368877b2e0e343d1d1da640894432d46c 100644 (file)
@@ -334,6 +334,7 @@ public:
         isc_throw(isc::NotImplemented,
                   "This test database knows nothing about NSEC3 nor order");
     }
+
 private:
     const std::string database_name_;
 
@@ -4097,4 +4098,26 @@ TYPED_TEST(DatabaseClientTest, findNSEC3) {
     performNSEC3Test(*finder, true);
 }
 
+TYPED_TEST(DatabaseClientTest, createZone) {
+    const Name new_name("example.com");
+    const DataSourceClient::FindResult
+        zone(this->client_->findZone(new_name));
+    ASSERT_EQ(result::NOTFOUND, zone.code);
+    // The mock implementation does not do createZone,
+    // in which case it should throw NotImplemented (from
+    // the base class)
+    if(this->is_mock_) {
+        ASSERT_THROW(this->client_->createZone(new_name), isc::NotImplemented);
+    } else {
+        // But in the real case, it should work and return true
+        ASSERT_TRUE(this->client_->createZone(new_name));
+        const DataSourceClient::FindResult
+            zone2(this->client_->findZone(new_name));
+        ASSERT_EQ(result::SUCCESS, zone2.code);
+        // And the second call should return false since
+        // it already exists
+        ASSERT_FALSE(this->client_->createZone(new_name));
+    }
+}
+
 }