Skip to content

Commit

Permalink
Add /v1/leader-redirect-by-node-name/ route
Browse files Browse the repository at this point in the history
  • Loading branch information
tailhook committed Apr 20, 2018
1 parent a388312 commit 3b77c54
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 3 deletions.
9 changes: 9 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ Verwalter Changes by Version
============================


.. _changelog-0.11.3:

Verwalter 0.11.3
----------------

* Feature: Added exerimental route ``/v1/leader-redirect-by-node-name/`` that
returns redirect to a leader node


.. _changelog-0.11.2:

Verwalter 0.11.2
Expand Down
63 changes: 60 additions & 3 deletions src/daemon/frontend/api.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use std::collections::{HashMap, HashSet};
use std::io::BufWriter;
use std::io::{Write, BufWriter};
use std::sync::Arc;
use std::time::SystemTime;
use std::time::{SystemTime, Duration};

use futures::future::{FutureResult, ok, Future};
use futures::future::{loop_fn, Loop::{Break, Continue}};
use futures::sync::oneshot;
use gron::json_to_gron;
use serde::Serialize;
use serde_json::{Value, to_writer, to_writer_pretty, to_value};
use serde_millis;
use tk_http::Status::{self, NotFound};
use tk_easyloop::timeout;
use tk_http::Status::{self, NotFound, PermanentRedirect};
use tk_http::Status::{TooManyRequests, ServiceUnavailable};
use tk_http::server::{Codec as CodecTrait};
use tk_http::server::{Encoder, EncoderDone, Error};
Expand Down Expand Up @@ -407,5 +409,60 @@ pub fn serve<S: 'static>(state: &SharedState, route: &ApiRoute, format: Format)
}))
}
Backup(..) | Backups => unreachable!(),
RedirectByNodeName => {
Ok(reply(move |mut e| {
Box::new(loop_fn(0, move |iter| {
let state = state.clone();
timeout(Duration::new(if iter > 0 { 1 } else { 0 }, 0))
.map_err(|_| unreachable!())
.and_then(move |()| {
let peers = state.peers();
let election = state.election();
if election.is_leader {
Ok(Break(Some(state.hostname.clone())))
} else {
match election.leader.as_ref()
.and_then(|id| peers.peers.get(id))
{
Some(peer) => {
Ok(Break(Some(peer.get().hostname.clone())))
}
None => {
if iter > 65 {
Ok(Break(None))
} else {
Ok(Continue(iter+1))
}
}
}
}
})
})
.and_then(move |hostname| {
if let Some(hostname) = hostname {
e.status(PermanentRedirect);
e.add_length(0).unwrap();
e.add_header("Cache-Control", "no-cache");
// TODO(tailhook) fix port
// TODO(tailhook) append tail url
e.format_header("Location",
format_args!("http://{}:8379/", hostname))
.unwrap();
e.done_headers().unwrap();
ok(e.done())
} else {
e.status(NotFound);
e.add_chunked().unwrap();
e.add_header("Cache-Control", "no-cache");
e.add_header("Content-Type", "text/plain").unwrap();
if e.done_headers().unwrap() {
write!(e, "No leader found in 65 seconds")
.unwrap();
}
ok(e.done())
}
}))
}))
}
}
}
4 changes: 4 additions & 0 deletions src/daemon/frontend/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub enum ApiRoute {
ActionIsPending(u64),
PendingActions,
ForceRenderAll,
RedirectByNodeName,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -113,6 +114,9 @@ fn parse_api(path: &str) -> Option<Route> {
use self::Format::Plain;
match path_component(path) {
("status", "") => Some(Api(Status, api_suffix(path))),
("leader-redirect-by-node-name", "") => {
Some(Api(RedirectByNodeName, Plain))
}
("peers", "") => Some(Api(Peers, api_suffix(path))),
("schedule", "") => Some(Api(Schedule, api_suffix(path))),
("scheduler_input", "") => Some(Api(SchedulerInput, api_suffix(path))),
Expand Down

0 comments on commit 3b77c54

Please sign in to comment.