]> granicus.if.org Git - pdns/commitdiff
Move current API path to /api/v1 from /
authorPieter Lexis <pieter.lexis@powerdns.com>
Tue, 1 Dec 2015 11:26:07 +0000 (12:26 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Tue, 1 Dec 2015 12:22:31 +0000 (13:22 +0100)
Closes #2612

docs/markdown/httpapi/README.md
docs/markdown/httpapi/api_spec.md
pdns/dnsdist-web.cc
pdns/ws-api.cc
pdns/ws-auth.cc
pdns/ws-recursor.cc
regression-tests.api/test_Basics.py
regression-tests.api/test_RecursorConfig.py
regression-tests.api/test_Servers.py
regression-tests.api/test_Zones.py

index bca389f7ebbc9a3a2783436a0e7b7a554308d823..24c269fd835d92ad5e415c5862586636969bb465 100644 (file)
@@ -30,16 +30,16 @@ Then configure as follows:
 After restarting `pdns_server`, the following examples should start working:
 
     # List zones
-    curl -H 'X-API-Key: changeme' http://127.0.0.1:8081/servers/localhost/zones | jq .
+    curl -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones | jq .
     
     # Create new zone "example.org" with nameservers ns1.example.org, ns2.example.org
-    curl -X POST --data '{"name":"example.org", "kind": "Native", "masters": [], "nameservers": ["ns1.example.org", "ns2.example.org"]}' -v -H 'X-API-Key: changeme' http://127.0.0.1:8081/servers/localhost/zones | jq .
+    curl -X POST --data '{"name":"example.org", "kind": "Native", "masters": [], "nameservers": ["ns1.example.org", "ns2.example.org"]}' -v -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones | jq .
     
     # Show the new zone
-    curl -H 'X-API-Key: changeme' http://127.0.0.1:8081/servers/localhost/zones/example.org | jq .
+    curl -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.org | jq .
     
     # Add a new record to the new zone (would replace any existing test.example.org/A records)
-    curl -X PATCH --data '{"rrsets": [ {"name": "test.example.org", "type": "A", "changetype": "REPLACE", "records": [ {"content": "192.0.5.4", "disabled": false, "name": "test.example.org", "ttl": 86400, "type": "A" } ] } ] }' -H 'X-API-Key: changeme' http://127.0.0.1:8081/servers/localhost/zones/example.org | jq .
+    curl -X PATCH --data '{"rrsets": [ {"name": "test.example.org", "type": "A", "changetype": "REPLACE", "records": [ {"content": "192.0.5.4", "disabled": false, "name": "test.example.org", "ttl": 86400, "type": "A" } ] } ] }' -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.org | jq .
 
     # Combined replacement of multiple RRsets
     curl -X PATCH --data '{"rrsets": [
@@ -53,7 +53,7 @@ After restarting `pdns_server`, the following examples should start working:
        "changetype": "REPLACE",
        "records": [ {"content": "2001:db8::6/32", "disabled": false, "name": "test.example.org", "ttl": 86400, "type": "AAAA" } ]
       }
-      ] }' -H 'X-API-Key: changeme' http://127.0.0.1:8081/servers/localhost/zones/example.org | jq .
+      ] }' -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.org | jq .
 
 `jq` is a highly recommended tool for pretty-printing JSON. If you don't have
 `jq`, try `json_pp` or `python -mjson.tool` instead.
@@ -81,8 +81,8 @@ Install PowerDNS Recursor, configured as follows:
 
 After restarting `pdns_recursor`, the following examples should start working:
 
-    curl -v -H 'X-API-Key: changeme' http://127.0.0.1:8082/servers/localhost | jq .
-    curl -v -H 'X-API-Key: changeme' http://127.0.0.1:8082/servers/localhost/zones | jq .
+    curl -v -H 'X-API-Key: changeme' http://127.0.0.1:8082/api/v1/servers/localhost | jq .
+    curl -v -H 'X-API-Key: changeme' http://127.0.0.1:8082/api/v1/servers/localhost/zones | jq .
 
 
 API Specification
index 184c20e218e3617f0ec1d44260cafcf4bbbcc1fe..3e0d19fb9810091422572452c15c0a12d5da2f82 100644 (file)
@@ -96,16 +96,16 @@ Common Error Causes
 
 1. The client body was not a JSON document, or it could not be parsed, or the root element of the JSON document was not a hash.
 2. The client did not send an `Accept:` header, or it was set to `*/*`.
-3. For requests that operate on a zone, the `zone_id` URL part was invalid. To get a valid `zone_id`, list the zones with the `/servers/:server_id/zones` endpoint.
+3. For requests that operate on a zone, the `zone_id` URL part was invalid. To get a valid `zone_id`, list the zones with the `/api/v1/servers/:server_id/zones` endpoint.
 
 
-URL: /
-------
+URL: /api/v1
+------------
 
 Allowed methods: `GET`
 
     {
-      "server_url": "/servers{/server}",
+      "server_url": "/api/v1/servers{/server}",
       "api_features": [],
     }
 
@@ -198,11 +198,11 @@ other servers.
     {
       "type": "Server",
       "id": "localhost",
-      "url": "/servers/localhost",
+      "url": "/api/v1/servers/localhost",
       "daemon_type": "recursor",
       "version": "VERSION",
-      "config_url": "/servers/localhost/config{/config_setting}",
-      "zones_url": "/servers/localhost/zones{/zone}",
+      "config_url": "/api/v1/servers/localhost/config{/config_setting}",
+      "zones_url": "/api/v1/servers/localhost/zones{/zone}",
     }
 
 Note: On a pdns server, the servers collection is read-only, and the only
@@ -215,7 +215,7 @@ depend on the credentials you have supplied.
   May be one of `authoritative`, `recursor`.
 
 
-URL: /servers
+URL: /api/v1/servers
 -------------
 
 Collection access.
@@ -227,7 +227,7 @@ Allowed REST methods:
 * pdnscontrol: `GET`, `PUT`, `POST`, `DELETE`
 
 
-URL: /servers/:server\_id
+URL: /api/v1/servers/:server\_id
 -------------------------
 
 Returns a single server_resource.
@@ -248,7 +248,7 @@ config\_setting\_resource
     }
 
 
-URL: /servers/:server\_id/config
+URL: /api/v1/servers/:server\_id/config
 --------------------------------
 
 Collection access.
@@ -262,7 +262,7 @@ Creates a new config setting. This is useful for creating configuration for new
 **TODO**: Not yet implemented.
 
 
-URL: /servers/:server\_id/config/:config\_setting\_name
+URL: /api/v1/servers/:server\_id/config/:config\_setting\_name
 -------------------------------------------------------
 
 Allowed REST methods: `GET`, `PUT`
@@ -287,7 +287,7 @@ zone_collection
       "id": "<id>",
       "name": "<string>",
       "type": "Zone",
-      "url": "/servers/:server_id/zones/:id",
+      "url": "/api/v1/servers/:server_id/zones/:id",
       "kind": "<kind>",
       "serial": <int>,
       "notified_serial": <int>,
@@ -384,7 +384,7 @@ When creating a slave zone, it is recommended to not set any of
 `nameservers`, `records`.
 
 
-URL: /servers/:server\_id/zones
+URL: /api/v1/servers/:server\_id/zones
 -------------------------------
 
 Allowed REST methods: `GET`, `POST`
@@ -405,7 +405,7 @@ rules before storing it. (Also applies to custom SOA records.)
 
 **TODO**: `dnssec`, `nsec3narrow`, `nsec3param`, `presigned` are not yet implemented.
 
-URL: /servers/:server\_id/zones/:zone\_id
+URL: /api/v1/servers/:server\_id/zones/:zone\_id
 -----------------------------------------
 
 Allowed methods: `GET`, `PUT`, `DELETE`, `PATCH`.
@@ -495,7 +495,7 @@ Allowed fields in client body: all except `id` and `url`.
 Changing `name` renames the zone, as expected.
 
 
-URL: /servers/:server\_id/zones/:zone\_id/notify
+URL: /api/v1/servers/:server\_id/zones/:zone\_id/notify
 ------------------------------------------------
 
 Allowed methods: `PUT`
@@ -510,7 +510,7 @@ Not supported for recursors.
 Clients MUST NOT send a body.
 
 
-URL: /servers/:server\_id/zones/:zone\_id/axfr-retrieve
+URL: /api/v1/servers/:server\_id/zones/:zone\_id/axfr-retrieve
 -------------------------------------------------------
 
 Allowed methods: `PUT`
@@ -525,7 +525,7 @@ Not supported for recursors.
 **Note**: Added in 3.4.2
 
 
-URL: /servers/:server\_id/zones/:zone\_id/export
+URL: /api/v1/servers/:server\_id/zones/:zone\_id/export
 -------------------------------------------------------
 
 Allowed methods: `GET`
@@ -535,7 +535,7 @@ Returns the zone in AXFR format.
 Not supported for recursors.
 
 
-URL: /servers/:server\_id/zones/:zone\_id/check
+URL: /api/v1/servers/:server\_id/zones/:zone\_id/check
 -----------------------------------------------
 
 Allowed methods: `GET`
@@ -574,7 +574,7 @@ through this interface. The server SHOULD reject updates to these
 metadata.
 
 
-URL: /servers/:server\_id/zones/:zone\_name/metadata
+URL: /api/v1/servers/:server\_id/zones/:zone\_name/metadata
 ----------------------------------------------------
 
 Collection access.
@@ -583,7 +583,7 @@ Allowed methods: `GET`, `POST`
 
 **TODO**: Not yet implemented.
 
-URL: /servers/:server\_id/zones/:zone\_name/metadata/:metadata\_kind
+URL: /api/v1/servers/:server\_id/zones/:zone\_name/metadata/:metadata\_kind
 --------------------------------------------------------------------
 
 Allowed methods: `GET`, `PUT`, `DELETE`
@@ -621,7 +621,7 @@ both mutually exclusive.
 `ds`: an array with all dses for this key
 
 
-URL: /servers/:server\_id/zones/:zone\_name/cryptokeys
+URL: /api/v1/servers/:server\_id/zones/:zone\_name/cryptokeys
 ------------------------------------------------------
 
 Allowed methods: `GET`, `POST`
@@ -648,7 +648,7 @@ Where `<algo>` is one of the supported key algos in lowercase OR the
 numeric id, see
 [http://rtfm.powerdns.com/pdnsutil.html](http://rtfm.powerdns.com/pdnsutil.html)
 
-URL: /servers/:server\_id/zones/:zone\_name/cryptokeys/:cryptokey\_id
+URL: /api/v1/servers/:server\_id/zones/:zone\_name/cryptokeys/:cryptokey\_id
 ---------------------------------------------------------------------
 
 Allowed methods: `GET`, `PUT`, `DELETE`
@@ -675,7 +675,7 @@ Cache Access
 Logging & Statistics
 ====================
 
-URL: /servers/:server\_id/search-log?q=:search\_term
+URL: /api/v1/servers/:server\_id/search-log?q=:search\_term
 ----------------------------------------------------
 
 Allowed methods: `GET` (Query)
@@ -689,7 +689,7 @@ Query the log, filtered by `:search_term`. Response body:
       ...
     ]
 
-URL: /servers/:server\_id/statistics
+URL: /api/v1/servers/:server\_id/statistics
 ------------------------------------
 
 Allowed methods: `GET` (Query)
@@ -711,7 +711,7 @@ The statistic entries are dependent on the daemon type.
 Values are returned as strings.
 
 
-URL: /servers/:server\_id/trace
+URL: /api/v1/servers/:server\_id/trace
 -------------------------------
 
 **TODO**: Not yet implemented.
@@ -741,7 +741,7 @@ Retrieve query tracing log and current config. Response body:
     }
 
 
-URL: /servers/:server\_id/failures
+URL: /api/v1/servers/:server\_id/failures
 ----------------------------------
 
 **TODO**: Not yet implemented.
@@ -878,7 +878,7 @@ Clears recursively all cached data ("plain" DNS + DNSSEC)
 
 **TODO**: should this be stored? (for history)
 
-URL: /servers/:server\_id/overrides
+URL: /api/v1/servers/:server\_id/overrides
 ----------------------------------
 
 **TODO**: Not yet implemented.
@@ -887,7 +887,7 @@ Collection access.
 
 Allowed Methods: `GET`, `POST`
 
-URL: /servers/:server\_id/overrides/:override\_id
+URL: /api/v1/servers/:server\_id/overrides/:override\_id
 -------------------------------------------------
 
 **TODO**: Not yet implemented.
index b2c6e23d9a3614f13e762e1b77265a158c845a5c..2e09fa37ef5d128398e0e59b173c8585b29a35ee 100644 (file)
@@ -113,7 +113,7 @@ static void connectionThread(int sock, ComboAddress remote, string password)
       resp.headers["Content-Type"] = "application/json";
       resp.body=my_json.dump();
     }
-    else if(req.url.path=="/servers/localhost") {
+    else if(req.url.path=="/api/v1/servers/localhost") {
       resp.status=200;
 
       Json::array servers;
index a03be15621f6c3aa73ed5a0090a77de37f97e36f..0d64d6782ea9b523a0dcd9f8a56bee9387ec9ad5 100644 (file)
@@ -86,12 +86,12 @@ static void fillServerDetail(Value& out, Value::AllocatorType& allocator)
   out.SetObject();
   out.AddMember("type", "Server", allocator);
   out.AddMember("id", "localhost", allocator);
-  out.AddMember("url", "/servers/localhost", allocator);
+  out.AddMember("url", "/api/v1/servers/localhost", allocator);
   out.AddMember("daemon_type", jdaemonType, allocator);
   Value jversion(getPDNSVersion().c_str(), allocator);
   out.AddMember("version", jversion, allocator);
-  out.AddMember("config_url", "/servers/localhost/config{/config_setting}", allocator);
-  out.AddMember("zones_url", "/servers/localhost/zones{/zone}", allocator);
+  out.AddMember("config_url", "/api/v1/servers/localhost/config{/config_setting}", allocator);
+  out.AddMember("zones_url", "/api/v1/servers/localhost/zones{/zone}", allocator);
 }
 
 void apiServer(HttpRequest* req, HttpResponse* resp) {
index 6942ea092d4be616aa475023ec35d1399c7081b9..a129483908334d4453678656dfdbbde0698a90c9 100644 (file)
@@ -296,7 +296,7 @@ static void fillZoneInfo(const DomainInfo& di, Value& jdi, Document& doc) {
   string zoneId = apiZoneNameToId(di.zone);
   Value jzoneId(zoneId.c_str(), doc.GetAllocator()); // copy
   jdi.AddMember("id", jzoneId, doc.GetAllocator());
-  string url = "/servers/localhost/zones/" + zoneId;
+  string url = "api/v1/servers/localhost/zones/" + zoneId;
   Value jurl(url.c_str(), doc.GetAllocator()); // copy
   jdi.AddMember("url", jurl, doc.GetAllocator());
   Value jname(di.zone.toString().c_str(), doc.GetAllocator()); // copy
@@ -1226,20 +1226,20 @@ void AuthWebServer::webThread()
 {
   try {
     if(::arg().mustDo("json-interface")) {
-      d_ws->registerApiHandler("/servers/localhost/config", &apiServerConfig);
-      d_ws->registerApiHandler("/servers/localhost/flush-cache", &apiServerFlushCache);
-      d_ws->registerApiHandler("/servers/localhost/search-log", &apiServerSearchLog);
-      d_ws->registerApiHandler("/servers/localhost/search-data", &apiServerSearchData);
-      d_ws->registerApiHandler("/servers/localhost/statistics", &apiServerStatistics);
-      d_ws->registerApiHandler("/servers/localhost/zones/<id>/axfr-retrieve", &apiServerZoneAxfrRetrieve);
-      d_ws->registerApiHandler("/servers/localhost/zones/<id>/cryptokeys/<key_id>", &apiZoneCryptokeys);
-      d_ws->registerApiHandler("/servers/localhost/zones/<id>/cryptokeys", &apiZoneCryptokeys);
-      d_ws->registerApiHandler("/servers/localhost/zones/<id>/export", &apiServerZoneExport);
-      d_ws->registerApiHandler("/servers/localhost/zones/<id>/notify", &apiServerZoneNotify);
-      d_ws->registerApiHandler("/servers/localhost/zones/<id>", &apiServerZoneDetail);
-      d_ws->registerApiHandler("/servers/localhost/zones", &apiServerZones);
-      d_ws->registerApiHandler("/servers/localhost", &apiServerDetail);
-      d_ws->registerApiHandler("/servers", &apiServer);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/config", &apiServerConfig);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/flush-cache", &apiServerFlushCache);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/search-log", &apiServerSearchLog);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/search-data", &apiServerSearchData);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/statistics", &apiServerStatistics);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/axfr-retrieve", &apiServerZoneAxfrRetrieve);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/cryptokeys/<key_id>", &apiZoneCryptokeys);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/cryptokeys", &apiZoneCryptokeys);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/export", &apiServerZoneExport);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/notify", &apiServerZoneNotify);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>", &apiServerZoneDetail);
+      d_ws->registerApiHandler("/api/v1/servers/localhost/zones", &apiServerZones);
+      d_ws->registerApiHandler("/api/v1/servers/localhost", &apiServerDetail);
+      d_ws->registerApiHandler("/api/v1/servers", &apiServer);
     }
     d_ws->registerWebHandler("/style.css", boost::bind(&AuthWebServer::cssfunction, this, _1, _2));
     d_ws->registerWebHandler("/", boost::bind(&AuthWebServer::indexfunction, this, _1, _2));
index f923f6e0f3291202a4dd0f6d27b1efe23cd8d4bd..7b3318f145399c34cb71ecc9d933d7c113114e6f 100644 (file)
@@ -146,7 +146,7 @@ static void fillZone(const DNSName& zonename, HttpResponse* resp)
   string zoneId = apiZoneNameToId(iter->first);
   Value jzoneid(zoneId.c_str(), doc.GetAllocator()); // copy
   doc.AddMember("id", jzoneid, doc.GetAllocator());
-  string url = "/servers/localhost/zones/" + zoneId;
+  string url = "/api/v1/servers/localhost/zones/" + zoneId;
   Value jurl(url.c_str(), doc.GetAllocator()); // copy
   doc.AddMember("url", jurl, doc.GetAllocator());
   Value jname(iter->first.toString().c_str(), doc.GetAllocator()); // copy
@@ -308,7 +308,7 @@ static void apiServerZones(HttpRequest* req, HttpResponse* resp)
     string zoneId = apiZoneNameToId(val.first);
     Value jzoneid(zoneId.c_str(), doc.GetAllocator()); // copy
     jdi.AddMember("id", jzoneid, doc.GetAllocator());
-    string url = "/servers/localhost/zones/" + zoneId;
+    string url = "/api/v1/servers/localhost/zones/" + zoneId;
     Value jurl(url.c_str(), doc.GetAllocator()); // copy
     jdi.AddMember("url", jurl, doc.GetAllocator());
     jdi.AddMember("name", val.first.toString().c_str(), doc.GetAllocator());
@@ -435,16 +435,16 @@ RecursorWebServer::RecursorWebServer(FDMultiplexer* fdm)
 
   // legacy dispatch
   d_ws->registerApiHandler("/jsonstat", boost::bind(&RecursorWebServer::jsonstat, this, _1, _2));
-  d_ws->registerApiHandler("/servers/localhost/flush-cache", &apiServerFlushCache);
-  d_ws->registerApiHandler("/servers/localhost/config/allow-from", &apiServerConfigAllowFrom);
-  d_ws->registerApiHandler("/servers/localhost/config", &apiServerConfig);
-  d_ws->registerApiHandler("/servers/localhost/search-log", &apiServerSearchLog);
-  d_ws->registerApiHandler("/servers/localhost/search-data", &apiServerSearchData);
-  d_ws->registerApiHandler("/servers/localhost/statistics", &apiServerStatistics);
-  d_ws->registerApiHandler("/servers/localhost/zones/<id>", &apiServerZoneDetail);
-  d_ws->registerApiHandler("/servers/localhost/zones", &apiServerZones);
-  d_ws->registerApiHandler("/servers/localhost", &apiServerDetail);
-  d_ws->registerApiHandler("/servers", &apiServer);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/flush-cache", &apiServerFlushCache);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/config/allow-from", &apiServerConfigAllowFrom);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/config", &apiServerConfig);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/search-log", &apiServerSearchLog);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/search-data", &apiServerSearchData);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/statistics", &apiServerStatistics);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>", &apiServerZoneDetail);
+  d_ws->registerApiHandler("/api/v1/servers/localhost/zones", &apiServerZones);
+  d_ws->registerApiHandler("/api/v1/servers/localhost", &apiServerDetail);
+  d_ws->registerApiHandler("/api/v1/servers", &apiServer);
 
   d_ws->go();
 }
index 79c3d9ecfdd975d998ec22f464c13c0436846121..a3d4d8136ca29af451a1bac247083ce8166f3df2 100644 (file)
@@ -7,7 +7,7 @@ from test_helper import ApiTestCase
 class TestBasics(ApiTestCase):
 
     def test_unauth(self):
-        r = requests.get(self.url("/servers/localhost"))
+        r = requests.get(self.url("/api/v1/servers/localhost"))
         self.assertEquals(r.status_code, requests.codes.unauthorized)
 
     def test_split_request(self):
@@ -33,7 +33,7 @@ class TestBasics(ApiTestCase):
             raise Exception('Got unwanted response: %s' % status)
 
     def test_cors(self):
-        r = self.session.options(self.url("/servers/localhost"))
+        r = self.session.options(self.url("/api/v1/servers/localhost"))
         # look for CORS headers
 
         self.assertEquals(r.status_code, requests.codes.ok)
index eeaa8a65088d3c50264ef2a456e85b3d9107fb92..2a3c1f11998ea8f91ade56d76bcceabba3cb1900 100644 (file)
@@ -7,13 +7,13 @@ from test_helper import ApiTestCase, is_recursor
 class RecursorConfig(ApiTestCase):
 
     def test_config_allow_from_get(self):
-        r = self.session.get(self.url("/servers/localhost/config/allow-from"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/config/allow-from"))
         self.assert_success_json(r)
 
     def test_config_allow_from_replace(self):
         payload = {'value': ["127.0.0.1"]}
         r = self.session.put(
-            self.url("/servers/localhost/config/allow-from"),
+            self.url("/api/v1/servers/localhost/config/allow-from"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -24,7 +24,7 @@ class RecursorConfig(ApiTestCase):
         """Test the error case, should return 422."""
         payload = {'value': ["abcdefgh"]}
         r = self.session.put(
-            self.url("/servers/localhost/config/allow-from"),
+            self.url("/api/v1/servers/localhost/config/allow-from"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assertEquals(r.status_code, 422)
index 36ef586f98f7216ae536fbad68e136bc135c570c..28067858fc86bb7035e1995f3b6202c7574f070c 100644 (file)
@@ -4,7 +4,7 @@ from test_helper import ApiTestCase, is_auth, is_recursor
 class Servers(ApiTestCase):
 
     def test_list_servers(self):
-        r = self.session.get(self.url("/servers"))
+        r = self.session.get(self.url("/api/v1/servers"))
         self.assert_success_json(r)
         lst = r.json()
         self.assertEquals(len(lst), 1)  # only localhost allowed in there
@@ -14,7 +14,7 @@ class Servers(ApiTestCase):
         self.assertEquals(data['id'], 'localhost')
 
     def test_servers_localhost(self):
-        r = self.session.get(self.url("/servers/localhost"))
+        r = self.session.get(self.url("/api/v1/servers/localhost"))
         self.assert_success_json(r)
         data = r.json()
         for k in ('id', 'type', 'version', 'daemon_type', 'url', 'zones_url', 'config_url'):
@@ -31,25 +31,25 @@ class Servers(ApiTestCase):
         self.assertEquals(data['daemon_type'], daemon_type)
 
     def test_read_config(self):
-        r = self.session.get(self.url("/servers/localhost/config"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/config"))
         self.assert_success_json(r)
         data = dict([(r['name'], r['value']) for r in r.json()])
         self.assertIn('daemon', data)
 
     def test_read_statistics(self):
-        r = self.session.get(self.url("/servers/localhost/statistics"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/statistics"))
         self.assert_success_json(r)
         data = dict([(r['name'], r['value']) for r in r.json()])
         self.assertIn('uptime', data)
 
     def test_flush_cache(self):
-        r = self.session.put(self.url("/servers/localhost/flush-cache?domain=example.org."))
+        r = self.session.put(self.url("/api/v1/servers/localhost/flush-cache?domain=example.org."))
         self.assert_success_json(r)
         data = r.json()
         self.assertIn('count', data)
 
     def test_flush_complete_cache(self):
-        r = self.session.put(self.url("/servers/localhost/flush-cache"))
+        r = self.session.put(self.url("/api/v1/servers/localhost/flush-cache"))
         self.assert_success_json(r)
         data = r.json()
         self.assertIn('count', data)
index 26f62e421fc03306c1d2dddec41a97f0e6a39fe8..e7aabbe30d7224fb6f5d2b2d70e8f6c19dabfef2 100644 (file)
@@ -7,7 +7,7 @@ from test_helper import ApiTestCase, unique_zone_name, is_auth, is_recursor
 class Zones(ApiTestCase):
 
     def test_list_zones(self):
-        r = self.session.get(self.url("/servers/localhost/zones"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         self.assert_success_json(r)
         domains = r.json()
         example_com = [domain for domain in domains if domain['name'] in ('example.com', 'example.com.')]
@@ -38,7 +38,7 @@ class AuthZonesHelperMixin(object):
                 payload[k] = v
         print payload
         r = self.session.post(
-            self.url("/servers/localhost/zones"),
+            self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -159,7 +159,7 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin):
         }
         print payload
         r = self.session.post(
-            self.url("/servers/localhost/zones"),
+            self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assertEquals(r.status_code, 422)
@@ -173,12 +173,12 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin):
         print "payload:", payload
         print "data:", data
         # Because slave zones don't get a SOA, we need to test that they'll show up in the zone list.
-        r = self.session.get(self.url("/servers/localhost/zones"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         zonelist = r.json()
         print "zonelist:", zonelist
         self.assertIn(payload['name'], [zone['name'] for zone in zonelist])
         # Also test that fetching the zone works.
-        r = self.session.get(self.url("/servers/localhost/zones/" + data['id']))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + data['id']))
         data = r.json()
         print "zone (fetched):", data
         for k in ('name', 'masters', 'kind'):
@@ -189,14 +189,14 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin):
 
     def test_delete_slave_zone(self):
         payload, data = self.create_zone(kind='Slave', nameservers=None, masters=['127.0.0.2'])
-        r = self.session.delete(self.url("/servers/localhost/zones/" + data['id']))
+        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + data['id']))
         r.raise_for_status()
 
     def test_retrieve_slave_zone(self):
         payload, data = self.create_zone(kind='Slave', nameservers=None, masters=['127.0.0.2'])
         print "payload:", payload
         print "data:", data
-        r = self.session.put(self.url("/servers/localhost/zones/" + data['id'] + "/axfr-retrieve"))
+        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data['id'] + "/axfr-retrieve"))
         data = r.json()
         print "status for axfr-retrieve:", data
         self.assertEqual(data['result'], u'Added retrieval request for \'' + payload['name'] +
@@ -206,7 +206,7 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin):
         payload, data = self.create_zone(kind='Master')
         print "payload:", payload
         print "data:", data
-        r = self.session.put(self.url("/servers/localhost/zones/" + data['id'] + "/notify"))
+        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data['id'] + "/notify"))
         data = r.json()
         print "status for notify:", data
         self.assertEqual(data['result'], 'Notification queued')
@@ -215,7 +215,7 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin):
         payload, data = self.create_zone(name='foo/bar.'+unique_zone_name())
         name = payload['name']
         zone_id = (name.replace('/', '=2F')) + '.'
-        r = self.session.get(self.url("/servers/localhost/zones/" + zone_id))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + zone_id))
         data = r.json()
         for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'dnssec'):
             self.assertIn(k, data)
@@ -223,10 +223,10 @@ class AuthZones(ApiTestCase, AuthZonesHelperMixin):
                 self.assertEquals(data[k], payload[k])
 
     def test_get_zone(self):
-        r = self.session.get(self.url("/servers/localhost/zones"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         domains = r.json()
         example_com = [domain for domain in domains if domain['name'] == u'example.com'][0]
-        r = self.session.get(self.url("/servers/localhost/zones/" + example_com['id']))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + example_com['id']))
         self.assert_success_json(r)
         data = r.json()
         for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial'):
@@ -258,7 +258,7 @@ powerdns-broken.com.           86400   IN      SOA     powerdnssec1.ds9a.nl. ahu
         payload['kind'] = 'Master'
         payload['nameservers'] = []
         r = self.session.post(
-            self.url("/servers/localhost/zones"),
+            self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assertEquals(r.status_code, 422)
@@ -288,7 +288,7 @@ powerdns.com.           86400   IN      SOA     powerdnssec1.ds9a.nl. ahu.ds9a.n
         payload['kind'] = 'Master'
         payload['nameservers'] = []
         r = self.session.post(
-            self.url("/servers/localhost/zones"),
+            self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -351,7 +351,7 @@ fred   IN  A      192.168.0.4
         payload['kind'] = 'Master'
         payload['nameservers'] = []
         r = self.session.post(
-            self.url("/servers/localhost/zones"),
+            self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -394,7 +394,7 @@ fred   IN  A      192.168.0.4
         name = payload['name']
         # export it
         r = self.session.get(
-            self.url("/servers/localhost/zones/" + name + "/export"),
+            self.url("/api/v1/servers/localhost/zones/" + name + "/export"),
             headers={'accept': 'application/json;q=0.9,*/*;q=0.8'}
         )
         self.assert_success_json(r)
@@ -411,7 +411,7 @@ fred   IN  A      192.168.0.4
         name = payload['name']
         # export it
         r = self.session.get(
-            self.url("/servers/localhost/zones/" + name + "/export"),
+            self.url("/api/v1/servers/localhost/zones/" + name + "/export"),
             headers={'accept': '*/*'}
         )
         data = r.text.strip().split("\n")
@@ -432,7 +432,7 @@ fred   IN  A      192.168.0.4
             'soa_edit': 'EPOCH'
         }
         r = self.session.put(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -447,7 +447,7 @@ fred   IN  A      192.168.0.4
             'soa_edit': ''
         }
         r = self.session.put(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -483,12 +483,12 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
         # verify that (only) the new record is there
-        r = self.session.get(self.url("/servers/localhost/zones/" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name))
         rrset['type'] = rrset['type'].upper()
         data = r.json()['records']
         recs = [rec for rec in data if rec['type'] == rrset['type'] and rec['name'] == rrset['name']]
@@ -515,12 +515,12 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
         # verify that (only) the new record is there
-        r = self.session.get(self.url("/servers/localhost/zones/" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name))
         data = r.json()['records']
         recs = [rec for rec in data if rec['type'] == rrset['type'] and rec['name'] == rrset['name']]
         self.assertEquals(recs, rrset['records'])
@@ -558,12 +558,12 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset1, rrset2]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
         # verify that all rrsets have been updated
-        r = self.session.get(self.url("/servers/localhost/zones/" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name))
         data = r.json()['records']
         recs1 = [rec for rec in data if rec['type'] == rrset1['type'] and rec['name'] == rrset1['name']]
         self.assertEquals(recs1, rrset1['records'])
@@ -581,12 +581,12 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
         # verify that the records are gone
-        r = self.session.get(self.url("/servers/localhost/zones/" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name))
         data = r.json()['records']
         recs = [rec for rec in data if rec['type'] == rrset['type'] and rec['name'] == rrset['name']]
         self.assertEquals(recs, [])
@@ -612,7 +612,7 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -621,7 +621,7 @@ fred   IN  A      192.168.0.4
         soa_serial1 = [rec for rec in r.json()['records'] if rec['type'] == 'SOA'][0]['content'].split()[2]
         self.assertNotEquals(soa_serial1, '1')
         # make sure domain is still in zone list (disabled SOA!)
-        r = self.session.get(self.url("/servers/localhost/zones"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         domains = r.json()
         self.assertEquals(len([domain for domain in domains if domain['name'] == name]), 1)
         # sleep 1sec to ensure the EPOCH value changes for the next request
@@ -630,7 +630,7 @@ fred   IN  A      192.168.0.4
         rrset['records'][0]['disabled'] = False
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -660,7 +660,7 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assertEquals(r.status_code, 422)
@@ -685,7 +685,7 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assertEquals(r.status_code, 422)
@@ -710,7 +710,7 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assertEquals(r.status_code, 422)
@@ -734,7 +734,7 @@ fred   IN  A      192.168.0.4
             ]
         }
         payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/servers/localhost/zones/" + name), data=json.dumps(payload),
+        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
                                headers={'content-type': 'application/json'})
         self.assertEquals(r.status_code, 422)
         self.assertIn('unknown type', r.json()['error'])
@@ -758,7 +758,7 @@ fred   IN  A      192.168.0.4
             ]
         }
         payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/servers/localhost/zones/" + name), data=json.dumps(payload),
+        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
                                headers={'content-type': 'application/json'})
         self.assertEquals(r.status_code, 422)
         self.assertIn('Not in expected format', r.json()['error'])
@@ -773,7 +773,7 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         print r.content
@@ -782,7 +782,7 @@ fred   IN  A      192.168.0.4
     def test_zone_delete(self):
         payload, zone = self.create_zone()
         name = payload['name']
-        r = self.session.delete(self.url("/servers/localhost/zones/" + name))
+        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + name))
         self.assertEquals(r.status_code, 204)
         self.assertNotIn('Content-Type', r.headers)
 
@@ -806,13 +806,13 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
         # make sure the comments have been set, and that the NS
         # records are still present
-        r = self.session.get(self.url("/servers/localhost/zones/" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name))
         data = r.json()
         print data
         self.assertNotEquals([r for r in data['records'] if r['type'] == 'NS'], [])
@@ -832,12 +832,12 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
         # make sure the NS records are still present
-        r = self.session.get(self.url("/servers/localhost/zones/" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name))
         data = r.json()
         print data
         self.assertNotEquals([r for r in data['records'] if r['type'] == 'NS'], [])
@@ -862,7 +862,7 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -883,12 +883,12 @@ fred   IN  A      192.168.0.4
         }
         payload2 = {'rrsets': [rrset2]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload2),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
         # make sure the comments still exist
-        r = self.session.get(self.url("/servers/localhost/zones/" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name))
         data = r.json()
         print data
         # fix up input data for comparison with assertEquals.
@@ -923,11 +923,11 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
-        r = self.session.get(self.url("/servers/localhost/zones/" + revzone))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + revzone))
         recs = r.json()['records']
         print recs
         revrec = [rec for rec in recs if rec['type'] == 'PTR']
@@ -963,11 +963,11 @@ fred   IN  A      192.168.0.4
         }
         payload = {'rrsets': [rrset]}
         r = self.session.patch(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
-        r = self.session.get(self.url("/servers/localhost/zones/" + revzone))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + revzone))
         recs = r.json()['records']
         print recs
         revrec = [rec for rec in recs if rec['type'] == 'PTR']
@@ -982,7 +982,7 @@ fred   IN  A      192.168.0.4
     def test_search_rr_exact_zone(self):
         name = unique_zone_name()
         self.create_zone(name=name)
-        r = self.session.get(self.url("/servers/localhost/search-data?q=" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=" + name))
         self.assert_success_json(r)
         print r.json()
         self.assertEquals(r.json(), [{u'object_type': u'zone', u'name': name, u'zone_id': name+'.'}])
@@ -990,7 +990,7 @@ fred   IN  A      192.168.0.4
     def test_search_rr_substring(self):
         name = 'search-rr-zone.name'
         self.create_zone(name=name)
-        r = self.session.get(self.url("/servers/localhost/search-data?q=*rr-zone*"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=*rr-zone*"))
         self.assert_success_json(r)
         print r.json()
         # should return zone, SOA, ns1, ns2
@@ -999,7 +999,7 @@ fred   IN  A      192.168.0.4
     def test_search_rr_case_insensitive(self):
         name = 'search-rr-insenszone.name'
         self.create_zone(name=name)
-        r = self.session.get(self.url("/servers/localhost/search-data?q=*rr-insensZONE*"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=*rr-insensZONE*"))
         self.assert_success_json(r)
         print r.json()
         # should return zone, SOA, ns1, ns2
@@ -1012,7 +1012,7 @@ class AuthRootZone(ApiTestCase, AuthZonesHelperMixin):
     def setUp(self):
         super(AuthRootZone, self).setUp()
         # zone name is not unique, so delete the zone before each individual test.
-        self.session.delete(self.url("/servers/localhost/zones/=2E"))
+        self.session.delete(self.url("/api/v1/servers/localhost/zones/=2E"))
 
     def test_create_zone(self):
         payload, data = self.create_zone(name='', serial=22, soa_edit_api='')
@@ -1028,13 +1028,13 @@ class AuthRootZone(ApiTestCase, AuthZonesHelperMixin):
             " 10800 3600 604800 3600"
         )
         # Regression test: verify zone list works
-        zonelist = self.session.get(self.url("/servers/localhost/zones")).json()
+        zonelist = self.session.get(self.url("/api/v1/servers/localhost/zones")).json()
         print "zonelist:", zonelist
         self.assertIn(payload['name'], [zone['name'] for zone in zonelist])
         # Also test that fetching the zone works.
         print "id:", data['id']
         self.assertEquals(data['id'], '=2E')
-        data = self.session.get(self.url("/servers/localhost/zones/" + data['id'])).json()
+        data = self.session.get(self.url("/api/v1/servers/localhost/zones/" + data['id'])).json()
         print "zone (fetched):", data
         for k in ('name', 'kind'):
             self.assertIn(k, data)
@@ -1053,7 +1053,7 @@ class AuthRootZone(ApiTestCase, AuthZonesHelperMixin):
             'soa_edit': 'EPOCH'
         }
         r = self.session.put(
-            self.url("/servers/localhost/zones/" + zone_id),
+            self.url("/api/v1/servers/localhost/zones/" + zone_id),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -1068,7 +1068,7 @@ class AuthRootZone(ApiTestCase, AuthZonesHelperMixin):
             'soa_edit': ''
         }
         r = self.session.put(
-            self.url("/servers/localhost/zones/" + zone_id),
+            self.url("/api/v1/servers/localhost/zones/" + zone_id),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -1093,7 +1093,7 @@ class RecursorZones(ApiTestCase):
             'recursion_desired': rd
         }
         r = self.session.post(
-            self.url("/servers/localhost/zones"),
+            self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -1141,7 +1141,7 @@ class RecursorZones(ApiTestCase):
             'recursion_desired': False
         }
         r = self.session.put(
-            self.url("/servers/localhost/zones/" + name),
+            self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
             headers={'content-type': 'application/json'})
         self.assert_success_json(r)
@@ -1152,14 +1152,14 @@ class RecursorZones(ApiTestCase):
     def test_zone_delete(self):
         payload, zone = self.create_zone(kind='Native')
         name = payload['name']
-        r = self.session.delete(self.url("/servers/localhost/zones/" + name))
+        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + name))
         self.assertEquals(r.status_code, 204)
         self.assertNotIn('Content-Type', r.headers)
 
     def test_search_rr_exact_zone(self):
         name = unique_zone_name() + '.'
         self.create_zone(name=name, kind='Native')
-        r = self.session.get(self.url("/servers/localhost/search-data?q=" + name))
+        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=" + name))
         self.assert_success_json(r)
         print r.json()
         self.assertEquals(r.json(), [{u'type': u'zone', u'name': name, u'zone_id': name}])
@@ -1167,7 +1167,7 @@ class RecursorZones(ApiTestCase):
     def test_search_rr_substring(self):
         name = 'search-rr-zone.name'
         self.create_zone(name=name, kind='Native')
-        r = self.session.get(self.url("/servers/localhost/search-data?q=rr-zone"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=rr-zone"))
         self.assert_success_json(r)
         print r.json()
         # should return zone, SOA